From 1a8d108040abbb419b12737cf6be2400ab344a00 Mon Sep 17 00:00:00 2001 From: Diogo Guerra Date: Thu, 3 Dec 2015 10:51:29 +0100 Subject: [PATCH 001/600] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8d4095415..a420f3fdc 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "facebook/webdriver", - "description": "A PHP client for WebDriver", + "name": "dguerra/facebook-webdriver", + "description": "A fork of Facebook PHP client for WebDriver", "keywords": ["webdriver", "selenium", "php", "facebook"], "homepage": "https://github.com/facebook/php-webdriver", "type": "library", From 912a5e528c2e545a44d9030f5fcb8bebf1446006 Mon Sep 17 00:00:00 2001 From: DGuerra Date: Thu, 3 Dec 2015 11:23:30 +0100 Subject: [PATCH 002/600] Added possibility to set RDF file --- lib/Firefox/FirefoxProfile.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index a7d926652..4ba192bb4 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -33,6 +33,11 @@ class FirefoxProfile { */ private $extensions = array(); + /** + * @var string + */ + private $rdfFile; + /** * @param string $extension The path to the xpi extension. * @return FirefoxProfile @@ -42,6 +47,19 @@ public function addExtension($extension) { return $this; } + /** + * @param string $rdfFile The path to the rdf file + * @return FirefoxProfile + */ + public function setRdfFile($rdfFile) { + if(!is_file($rdfFile)) { + return; + } + + $this->rdfFile = $rdfFile; + return $this; + } + /** * @param string $key * @param string|bool|int $value @@ -69,6 +87,10 @@ public function setPreference($key, $value) { public function encode() { $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile'); + if(isset($this->rdfFile)) { + copy($this->rdfFile, $temp_dir . DIRECTORY_SEPARATOR . "mimeTypes.rdf"); + } + foreach ($this->extensions as $extension) { $this->installExtension($extension, $temp_dir); } From 8865a365d3e9fe9ccd9b9395c56e38f257191116 Mon Sep 17 00:00:00 2001 From: DGuerra Date: Thu, 3 Dec 2015 11:32:09 +0100 Subject: [PATCH 003/600] Added possibility to add datas for extensions --- lib/Firefox/FirefoxProfile.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 4ba192bb4..b1d0d5b23 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -33,6 +33,11 @@ class FirefoxProfile { */ private $extensions = array(); + /** + * @var array + */ + private $extensionsDatas = array(); + /** * @var string */ @@ -47,6 +52,19 @@ public function addExtension($extension) { return $this; } + /** + * @param string $extensionDatas The path to the folder containing the datas to add to the extension + * @return FirefoxProfile + */ + public function addExtensionDatas($extensionDatas) { + if(!is_dir($extensionDatas)) { + return; + } + + $this->extensionsDatas[dirname($extensionDatas)] = $extensionDatas; + return $this; + } + /** * @param string $rdfFile The path to the rdf file * @return FirefoxProfile @@ -95,6 +113,17 @@ public function encode() { $this->installExtension($extension, $temp_dir); } + foreach ($this->extensionsDatas as $dirname => $extensionDatas) { + mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname); + $files = scandir($extensionDatas); + foreach ($files as $file) { + if(is_file($file) + && $file != "." + && $file != "..") { + copy($extensionDatas . DIRECTORY_SEPARATOR . $file, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $file); + } + } + $content = ""; foreach ($this->preferences as $key => $value) { $content .= sprintf("user_pref(\"%s\", %s);\n", $key, $value); From 26440448164ca03e4d7664316112785ec52c88ea Mon Sep 17 00:00:00 2001 From: DGuerra Date: Thu, 3 Dec 2015 11:35:22 +0100 Subject: [PATCH 004/600] Renamed added vars to follow convention used by the others ones --- lib/Firefox/FirefoxProfile.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index b1d0d5b23..6b356ecd9 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -36,12 +36,12 @@ class FirefoxProfile { /** * @var array */ - private $extensionsDatas = array(); + private $extensions_datas = array(); /** * @var string */ - private $rdfFile; + private $rdf_file; /** * @param string $extension The path to the xpi extension. @@ -53,28 +53,28 @@ public function addExtension($extension) { } /** - * @param string $extensionDatas The path to the folder containing the datas to add to the extension + * @param string $extension_datas The path to the folder containing the datas to add to the extension * @return FirefoxProfile */ - public function addExtensionDatas($extensionDatas) { - if(!is_dir($extensionDatas)) { + public function addExtensionDatas($extension_datas) { + if(!is_dir($extension_datas)) { return; } - $this->extensionsDatas[dirname($extensionDatas)] = $extensionDatas; + $this->extensions_datas[dirname($extension_datas)] = $extension_datas; return $this; } /** - * @param string $rdfFile The path to the rdf file + * @param string $rdf_file The path to the rdf file * @return FirefoxProfile */ - public function setRdfFile($rdfFile) { - if(!is_file($rdfFile)) { + public function setRdfFile($rdf_file) { + if(!is_file($rdf_file)) { return; } - $this->rdfFile = $rdfFile; + $this->rdf_file = $rdf_file; return $this; } @@ -105,22 +105,22 @@ public function setPreference($key, $value) { public function encode() { $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile'); - if(isset($this->rdfFile)) { - copy($this->rdfFile, $temp_dir . DIRECTORY_SEPARATOR . "mimeTypes.rdf"); + if(isset($this->rdf_file)) { + copy($this->rdf_file, $temp_dir . DIRECTORY_SEPARATOR . "mimeTypes.rdf"); } foreach ($this->extensions as $extension) { $this->installExtension($extension, $temp_dir); } - foreach ($this->extensionsDatas as $dirname => $extensionDatas) { + foreach ($this->extensions_datas as $dirname => $extension_datas) { mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname); - $files = scandir($extensionDatas); + $files = scandir($extension_datas); foreach ($files as $file) { if(is_file($file) && $file != "." && $file != "..") { - copy($extensionDatas . DIRECTORY_SEPARATOR . $file, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $file); + copy($extension_datas . DIRECTORY_SEPARATOR . $file, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $file); } } From 2d2588d6bb7873b250047766492c7ab77410ccec Mon Sep 17 00:00:00 2001 From: DGuerra Date: Thu, 3 Dec 2015 11:37:20 +0100 Subject: [PATCH 005/600] Added prefix to extension temporary directory --- lib/Firefox/FirefoxProfile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 6b356ecd9..f23ddadde 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -165,7 +165,7 @@ public function encode() { * @return string The path to the directory of this extension. */ private function installExtension($extension, $profile_dir) { - $temp_dir = $this->createTempDirectory(); + $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfileExtension'); $this->extractTo($extension, $temp_dir); From 77289453ac3f33586e1f1aadb9a83f98e7c58aa5 Mon Sep 17 00:00:00 2001 From: DGuerra Date: Thu, 3 Dec 2015 11:54:27 +0100 Subject: [PATCH 006/600] Corrected forgotten bracket --- lib/Firefox/FirefoxProfile.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index f23ddadde..fe21c2e99 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -121,6 +121,7 @@ public function encode() { && $file != "." && $file != "..") { copy($extension_datas . DIRECTORY_SEPARATOR . $file, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $file); + } } } From d23382b50acf85d3bf7f76b9c5b4956660aa91ae Mon Sep 17 00:00:00 2001 From: DGuerra Date: Thu, 3 Dec 2015 14:19:22 +0100 Subject: [PATCH 007/600] Using correct function to get extension datas directory name --- lib/Firefox/FirefoxProfile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index fe21c2e99..62c809f84 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -61,7 +61,7 @@ public function addExtensionDatas($extension_datas) { return; } - $this->extensions_datas[dirname($extension_datas)] = $extension_datas; + $this->extensions_datas[basename($extension_datas)] = $extension_datas; return $this; } From 7b1af60eb964450f10c3d9f42d810749786b4398 Mon Sep 17 00:00:00 2001 From: DGuerra Date: Fri, 4 Dec 2015 00:05:39 +0100 Subject: [PATCH 008/600] Extension datas directories added recursively --- composer.json | 4 ++-- lib/Firefox/FirefoxProfile.php | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index a420f3fdc..8d4095415 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "dguerra/facebook-webdriver", - "description": "A fork of Facebook PHP client for WebDriver", + "name": "facebook/webdriver", + "description": "A PHP client for WebDriver", "keywords": ["webdriver", "selenium", "php", "facebook"], "homepage": "https://github.com/facebook/php-webdriver", "type": "library", diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 62c809f84..3d7739f5c 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -57,7 +57,7 @@ public function addExtension($extension) { * @return FirefoxProfile */ public function addExtensionDatas($extension_datas) { - if(!is_dir($extension_datas)) { + if (!is_dir($extension_datas)) { return; } @@ -70,7 +70,7 @@ public function addExtensionDatas($extension_datas) { * @return FirefoxProfile */ public function setRdfFile($rdf_file) { - if(!is_file($rdf_file)) { + if (!is_file($rdf_file)) { return; } @@ -105,7 +105,7 @@ public function setPreference($key, $value) { public function encode() { $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile'); - if(isset($this->rdf_file)) { + if (isset($this->rdf_file)) { copy($this->rdf_file, $temp_dir . DIRECTORY_SEPARATOR . "mimeTypes.rdf"); } @@ -115,13 +115,13 @@ public function encode() { foreach ($this->extensions_datas as $dirname => $extension_datas) { mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname); - $files = scandir($extension_datas); - foreach ($files as $file) { - if(is_file($file) - && $file != "." - && $file != "..") { - copy($extension_datas . DIRECTORY_SEPARATOR . $file, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $file); - } + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($extension_datas, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $item) { + if ($item->isDir()) { + mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); + } else { + copy($item, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); + } } } From 3f9606a43831d1ccc0befb1570eeefb2b30049a1 Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Tue, 8 Dec 2015 08:35:18 -0800 Subject: [PATCH 009/600] Check isset for timeout in seconds --- lib/WebDriverWait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WebDriverWait.php b/lib/WebDriverWait.php index 4b43b3755..5cddd29c3 100644 --- a/lib/WebDriverWait.php +++ b/lib/WebDriverWait.php @@ -35,7 +35,7 @@ public function __construct( $timeout_in_second = null, $interval_in_millisecond = null) { $this->driver = $driver; - $this->timeout = $timeout_in_second ?: 30; + $this->timeout = isset($timeout_in_second) ? $timeout_in_second : 30; $this->interval = $interval_in_millisecond ?: 250; } From ee78deaa5aa8cdc8c767f79bef834b17d0f70088 Mon Sep 17 00:00:00 2001 From: Tobias Kappe Date: Thu, 24 Dec 2015 14:47:58 +0100 Subject: [PATCH 010/600] Use sys_get_temp_dir rather than the empty string when calling tempnam. The latter fails when using the empty string if an open_basedir restriction is in effect. --- lib/Firefox/FirefoxProfile.php | 4 ++-- lib/Remote/RemoteWebElement.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 3d7739f5c..423bad924 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -132,7 +132,7 @@ public function encode() { file_put_contents($temp_dir.'/user.js', $content); $zip = new ZipArchive(); - $temp_zip = tempnam('', 'WebDriverFirefoxProfileZip'); + $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverFirefoxProfileZip'); $zip->open($temp_zip, ZipArchive::CREATE); $dir = new RecursiveDirectoryIterator($temp_dir); @@ -195,7 +195,7 @@ private function installExtension($extension, $profile_dir) { * @throws WebDriverException */ private function createTempDirectory($prefix = '') { - $temp_dir = tempnam('', $prefix); + $temp_dir = tempnam(sys_get_temp_dir(), $prefix); if (file_exists($temp_dir)) { unlink($temp_dir); mkdir($temp_dir); diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 235e3872c..e9e1ca31e 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -332,7 +332,7 @@ private function upload($local_file) { } // Create a temporary file in the system temp directory. - $temp_zip = tempnam('', 'WebDriverZip'); + $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip'); $zip = new ZipArchive(); if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) { return false; From 64485b2f068f6198261793fe62582cc2d1a0cd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 30 Dec 2015 14:01:01 +0100 Subject: [PATCH 011/600] Fix strict standards error --- lib/Chrome/ChromeDriver.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 67427205d..0cabccd91 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -56,18 +56,15 @@ public function startSession($desired_capabilities) { /** * Always throws an exception. Use ChromeDriver::start() instead. * - * @param string $url The url of the remote server - * @param DesiredCapabilities $desired_capabilities The desired capabilities - * @param int|null $timeout_in_ms - * @param int|null $request_timeout_in_ms - * * @throws WebDriverException */ public static function create( $url = 'http://localhost:4444/wd/hub', $desired_capabilities = null, - $timeout_in_ms = null, - $request_timeout_in_ms = null + $connection_timeout_in_ms = null, + $request_timeout_in_ms = null, + $http_proxy = null, + $http_proxy_port = null ) { throw new WebDriverException('Please use ChromeDriver::start() instead.'); } From 4967a61f12858ebfab64e77c4c44826fc256b351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 30 Dec 2015 18:48:44 +0100 Subject: [PATCH 012/600] Move tests to appropriate folders, use namespaces, improve phpdoc --- composer.json | 5 +++-- .../WebDriverButtonReleaseActionTest.php | 12 +++++++----- .../Internal}/WebDriverClickActionTest.php | 12 +++++++----- .../Internal}/WebDriverClickAndHoldActionTest.php | 12 +++++++----- .../Internal}/WebDriverContextClickActionTest.php | 12 +++++++----- .../Internal}/WebDriverCoordinatesTest.php | 2 +- .../Internal}/WebDriverDoubleClickActionTest.php | 12 +++++++----- .../Internal}/WebDriverKeyDownActionTest.php | 14 +++++++++----- .../Internal}/WebDriverKeyUpActionTest.php | 14 +++++++++----- .../Internal}/WebDriverMouseMoveActionTest.php | 12 +++++++----- .../WebDriverMouseToOffsetActionTest.php | 8 ++++++-- .../Internal}/WebDriverSendKeysActionTest.php | 15 ++++++++++----- 12 files changed, 80 insertions(+), 50 deletions(-) rename tests/unit/{ => Interactions/Internal}/WebDriverButtonReleaseActionTest.php (82%) rename tests/unit/{ => Interactions/Internal}/WebDriverClickActionTest.php (82%) rename tests/unit/{ => Interactions/Internal}/WebDriverClickAndHoldActionTest.php (82%) rename tests/unit/{ => Interactions/Internal}/WebDriverContextClickActionTest.php (83%) rename tests/unit/{ => Interactions/Internal}/WebDriverCoordinatesTest.php (95%) rename tests/unit/{ => Interactions/Internal}/WebDriverDoubleClickActionTest.php (83%) rename tests/unit/{ => Interactions/Internal}/WebDriverKeyDownActionTest.php (80%) rename tests/unit/{ => Interactions/Internal}/WebDriverKeyUpActionTest.php (80%) rename tests/unit/{ => Interactions/Internal}/WebDriverMouseMoveActionTest.php (83%) rename tests/unit/{ => Interactions/Internal}/WebDriverMouseToOffsetActionTest.php (85%) rename tests/unit/{ => Interactions/Internal}/WebDriverSendKeysActionTest.php (80%) diff --git a/composer.json b/composer.json index 8d4095415..be4ba7dd5 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ }, "autoload-dev": { "psr-4": { - "Facebook\\WebDriver\\": "tests/functional" - } + "Facebook\\WebDriver\\": "tests/unit" + }, + "classmap": ["tests/functional/"] } } diff --git a/tests/unit/WebDriverButtonReleaseActionTest.php b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php similarity index 82% rename from tests/unit/WebDriverButtonReleaseActionTest.php rename to tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php index 88e65b9f1..982e8d268 100644 --- a/tests/unit/WebDriverButtonReleaseActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverButtonReleaseAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverButtonReleaseActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverButtonReleaseAction - */ + /** @var WebDriverButtonReleaseAction */ private $webDriverButtonReleaseAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php similarity index 82% rename from tests/unit/WebDriverClickActionTest.php rename to tests/unit/Interactions/Internal/WebDriverClickActionTest.php index b69b0bb69..8fab683fe 100644 --- a/tests/unit/WebDriverClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverClickAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverClickActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverClickAction - */ + /** @var WebDriverClickAction */ private $webDriverClickAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverClickAndHoldActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php similarity index 82% rename from tests/unit/WebDriverClickAndHoldActionTest.php rename to tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php index 191337cb3..b10ac2cea 100644 --- a/tests/unit/WebDriverClickAndHoldActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverClickAndHoldActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverClickAndHoldAction - */ + /** @var WebDriverClickAndHoldAction */ private $webDriverClickAndHoldAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverContextClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php similarity index 83% rename from tests/unit/WebDriverContextClickActionTest.php rename to tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php index 1a23c6a19..a57cb127a 100644 --- a/tests/unit/WebDriverContextClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverContextClickAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverContextClickActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverContextClickAction - */ + /** @var WebDriverContextClickAction */ private $webDriverContextClickAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverCoordinatesTest.php b/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php similarity index 95% rename from tests/unit/WebDriverCoordinatesTest.php rename to tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php index 5371cc795..d38c7220a 100644 --- a/tests/unit/WebDriverCoordinatesTest.php +++ b/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates; +namespace Facebook\WebDriver\Interactions\Internal; class WebDriverCoordinatesTest extends \PHPUnit_Framework_TestCase { public function testConstruct() { diff --git a/tests/unit/WebDriverDoubleClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php similarity index 83% rename from tests/unit/WebDriverDoubleClickActionTest.php rename to tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php index 5904363fd..7f09f64dc 100644 --- a/tests/unit/WebDriverDoubleClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverDoubleClickActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverDoubleClickAction - */ + /** @var WebDriverDoubleClickAction */ private $webDriverDoubleClickAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverKeyDownActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php similarity index 80% rename from tests/unit/WebDriverKeyDownActionTest.php rename to tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php index ad1178432..5bba82f4f 100644 --- a/tests/unit/WebDriverKeyDownActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php @@ -13,16 +13,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverKeyboard; +use Facebook\WebDriver\WebDriverMouse; class WebDriverKeyDownActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverKeyDownAction - */ + /** @var WebDriverKeyDownAction */ private $webDriverKeyDownAction; - + /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverKeyboard; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverKeyUpActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php similarity index 80% rename from tests/unit/WebDriverKeyUpActionTest.php rename to tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php index 24e61638e..cd2b7b00c 100644 --- a/tests/unit/WebDriverKeyUpActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php @@ -13,16 +13,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverKeyUpAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverKeyboard; +use Facebook\WebDriver\WebDriverMouse; class WebDriverKeyUpActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverKeyUpAction - */ + /** @var WebDriverKeyUpAction */ private $webDriverKeyUpAction; - + /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverKeyboard; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverMouseMoveActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php similarity index 83% rename from tests/unit/WebDriverMouseMoveActionTest.php rename to tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php index 09f368e4b..6376adfa0 100644 --- a/tests/unit/WebDriverMouseMoveActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverMouseMoveActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverMouseMoveAction - */ + /** @var WebDriverMouseMoveAction */ private $webDriverMouseMoveAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverMouseToOffsetActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php similarity index 85% rename from tests/unit/WebDriverMouseToOffsetActionTest.php rename to tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php index 03f0b5e4c..2ea16d552 100644 --- a/tests/unit/WebDriverMouseToOffsetActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php @@ -13,15 +13,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; class WebDriverMouseToOffsetActionTest extends \PHPUnit_Framework_TestCase { /** * @type WebDriverMoveToOffsetAction */ private $webDriverMoveToOffsetAction; - + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; public function setUp() { diff --git a/tests/unit/WebDriverSendKeysActionTest.php b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php similarity index 80% rename from tests/unit/WebDriverSendKeysActionTest.php rename to tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php index ca6ea0df9..f7c2917d0 100644 --- a/tests/unit/WebDriverSendKeysActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php @@ -13,17 +13,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction; +namespace Facebook\WebDriver\Interactions\Internal; + +use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverKeyboard; +use Facebook\WebDriver\WebDriverMouse; class WebDriverSendKeysActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverSendKeysAction - */ + /** @var WebDriverSendKeysAction */ private $webDriverSendKeysAction; - + /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverKeyboard; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ private $locationProvider; + /** @var array */ private $keys; public function setUp() { From 07ab9b5c336038266b0164cc628dbf37d032bc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 30 Dec 2015 18:56:48 +0100 Subject: [PATCH 013/600] Minor codestyle fixes --- lib/Chrome/ChromeOptions.php | 6 ++--- lib/Firefox/FirefoxDriver.php | 5 +++- lib/Firefox/FirefoxProfile.php | 4 ++-- lib/Remote/DriverCommand.php | 10 ++++---- lib/Remote/RemoteWebDriver.php | 2 +- lib/Remote/Service/DriverCommandExecutor.php | 3 +-- lib/Remote/WebDriverBrowserType.php | 5 +++- lib/Remote/WebDriverCapabilityType.php | 8 ++++--- lib/Remote/WebDriverCommand.php | 18 ++++++++++++++- lib/WebDriverPlatform.php | 5 +++- phpunit.xml.dist | 24 +++++++++++--------- 11 files changed, 58 insertions(+), 32 deletions(-) diff --git a/lib/Chrome/ChromeOptions.php b/lib/Chrome/ChromeOptions.php index 5cc125f56..da387c55a 100644 --- a/lib/Chrome/ChromeOptions.php +++ b/lib/Chrome/ChromeOptions.php @@ -85,8 +85,7 @@ public function addExtensions(array $paths) { } /** - * @param array $encoded_extensions An array of base64 encoded of the - * extensions. + * @param array $encoded_extensions An array of base64 encoded of the extensions. * @return ChromeOptions */ public function addEncodedExtensions(array $encoded_extensions) { @@ -109,8 +108,7 @@ public function setExperimentalOption($name, $value) { } /** - * @return DesiredCapabilities The DesiredCapabilities for Chrome with this - * options. + * @return DesiredCapabilities The DesiredCapabilities for Chrome with this options. */ public function toCapabilities() { $capabilities = DesiredCapabilities::chrome(); diff --git a/lib/Firefox/FirefoxDriver.php b/lib/Firefox/FirefoxDriver.php index 8afbe0c2d..083af226b 100644 --- a/lib/Firefox/FirefoxDriver.php +++ b/lib/Firefox/FirefoxDriver.php @@ -16,6 +16,9 @@ namespace Facebook\WebDriver\Firefox; class FirefoxDriver { - const PROFILE = 'firefox_profile'; + + private function __construct() + { + } } diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 3d7739f5c..163d06049 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -55,7 +55,7 @@ public function addExtension($extension) { /** * @param string $extension_datas The path to the folder containing the datas to add to the extension * @return FirefoxProfile - */ + */ public function addExtensionDatas($extension_datas) { if (!is_dir($extension_datas)) { return; @@ -73,7 +73,7 @@ public function setRdfFile($rdf_file) { if (!is_file($rdf_file)) { return; } - + $this->rdf_file = $rdf_file; return $this; } diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index 61ad9d515..18e9fb37b 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -19,7 +19,6 @@ * This list of command defined in the WebDriver json wire protocol. */ class DriverCommand { - const GET_ALL_SESSIONS = "getAllSessions"; const GET_CAPABILITIES = "getCapabilities"; const NEW_SESSION = "newSession"; @@ -126,16 +125,14 @@ class DriverCommand { const SET_SCREEN_ORIENTATION = "setScreenOrientation"; const GET_SCREEN_ORIENTATION = "getScreenOrientation"; - // These belong to the Advanced user interactions - an element is - // optional for these commands. + // These belong to the Advanced user interactions - an element is optional for these commands. const CLICK = "mouseClick"; const DOUBLE_CLICK = "mouseDoubleClick"; const MOUSE_DOWN = "mouseButtonDown"; const MOUSE_UP = "mouseButtonUp"; const MOVE_TO = "mouseMoveTo"; - // Those allow interactions with the Input Methods installed on - // the system. + // Those allow interactions with the Input Methods installed on the system. const IME_GET_AVAILABLE_ENGINES = "imeGetAvailableEngines"; const IME_GET_ACTIVE_ENGINE = "imeGetActiveEngine"; const IME_IS_ACTIVATED = "imeIsActivated"; @@ -168,4 +165,7 @@ class DriverCommand { const GET_NETWORK_CONNECTION = "getNetworkConnection"; const SET_NETWORK_CONNECTION = "setNetworkConnection"; + private function __construct() + { + } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index ad253e701..1fda245b2 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -74,7 +74,7 @@ public static function create( ) { $url = preg_replace('#/+$#', '', $url); - // Passing DesiredCapabilities as $desired_capabilities is encourged but + // Passing DesiredCapabilities as $desired_capabilities is encouraged but // array is also accepted for legacy reason. if ($desired_capabilities instanceof DesiredCapabilities) { $desired_capabilities = $desired_capabilities->toArray(); diff --git a/lib/Remote/Service/DriverCommandExecutor.php b/lib/Remote/Service/DriverCommandExecutor.php index 10ab2b90f..2ac3414f1 100644 --- a/lib/Remote/Service/DriverCommandExecutor.php +++ b/lib/Remote/Service/DriverCommandExecutor.php @@ -38,13 +38,12 @@ public function __construct(DriverService $service) { /** * @param WebDriverCommand $command - * @param array $curl_opts * * @return mixed * @throws WebDriverException * @throws \Exception */ - public function execute(WebDriverCommand $command, $curl_opts = array()) { + public function execute(WebDriverCommand $command) { if ($command->getName() === DriverCommand::NEW_SESSION) { $this->service->start(); } diff --git a/lib/Remote/WebDriverBrowserType.php b/lib/Remote/WebDriverBrowserType.php index 5ab1df391..a9de79143 100644 --- a/lib/Remote/WebDriverBrowserType.php +++ b/lib/Remote/WebDriverBrowserType.php @@ -19,7 +19,6 @@ * All the browsers supported by selenium */ class WebDriverBrowserType { - const FIREFOX = "firefox"; const FIREFOX_2 = "firefox2"; const FIREFOX_3 = "firefox3"; @@ -42,4 +41,8 @@ class WebDriverBrowserType { const IPHONE = "iphone"; const IPAD = "iPad"; const PHANTOMJS = "phantomjs"; + + private function __construct() + { + } } diff --git a/lib/Remote/WebDriverCapabilityType.php b/lib/Remote/WebDriverCapabilityType.php index 552db09be..459952364 100644 --- a/lib/Remote/WebDriverCapabilityType.php +++ b/lib/Remote/WebDriverCapabilityType.php @@ -16,11 +16,9 @@ namespace Facebook\WebDriver\Remote; /** - * WebDriverCapabilityType contains all constants defined in the WebDriver - * Wire Protocol. + * WebDriverCapabilityType contains all constants defined in the WebDriver Wire Protocol. */ class WebDriverCapabilityType { - const BROWSER_NAME = 'browserName'; const VERSION = 'version'; const PLATFORM = 'platform'; @@ -37,4 +35,8 @@ class WebDriverCapabilityType { const ACCEPT_SSL_CERTS = 'acceptSslCerts'; const NATIVE_EVENTS = 'nativeEvents'; const PROXY = 'proxy'; + + private function __construct() + { + } } diff --git a/lib/Remote/WebDriverCommand.php b/lib/Remote/WebDriverCommand.php index 303af3cfb..cb90d2b64 100644 --- a/lib/Remote/WebDriverCommand.php +++ b/lib/Remote/WebDriverCommand.php @@ -16,25 +16,41 @@ namespace Facebook\WebDriver\Remote; class WebDriverCommand { - + /** @var string */ private $sessionID; + /** @var string */ private $name; + /** @var array */ private $parameters; + /** + * @param string $session_id + * @param string $name Constant from DriverCommand + * @param array $parameters Array of + */ public function __construct($session_id, $name, $parameters) { $this->sessionID = $session_id; $this->name = $name; $this->parameters = $parameters; } + /** + * @return string + */ public function getName() { return $this->name; } + /** + * @return string + */ public function getSessionID() { return $this->sessionID; } + /** + * @return array + */ public function getParameters() { return $this->parameters; } diff --git a/lib/WebDriverPlatform.php b/lib/WebDriverPlatform.php index 4954bf56e..9dc42fabd 100644 --- a/lib/WebDriverPlatform.php +++ b/lib/WebDriverPlatform.php @@ -19,7 +19,6 @@ * The platforms supported by WebDriver. */ class WebDriverPlatform { - const ANDROID = 'ANDROID'; const ANY = 'ANY'; const LINUX = 'LINUX'; @@ -28,4 +27,8 @@ class WebDriverPlatform { const VISTA = 'VISTA'; const WINDOWS = 'WINDOWS'; const XP = 'XP'; + + private function __construct() + { + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4dfdec0a7..83eb0ecef 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -2,18 +2,20 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.6/phpunit.xsd" + backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + bootstrap="tests/bootstrap.php" + > - + tests/unit From ef5d08965a1b641e53d38dafe34617462e31a839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 30 Dec 2015 19:22:40 +0100 Subject: [PATCH 014/600] Define constants with common Firefox profile preferences --- lib/Firefox/FirefoxPreferences.php | 33 ++++++++++++++++++++++++++++++ lib/Firefox/FirefoxProfile.php | 13 ++++++++++++ lib/Remote/DesiredCapabilities.php | 3 ++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 lib/Firefox/FirefoxPreferences.php diff --git a/lib/Firefox/FirefoxPreferences.php b/lib/Firefox/FirefoxPreferences.php new file mode 100644 index 000000000..6b7ca91dd --- /dev/null +++ b/lib/Firefox/FirefoxPreferences.php @@ -0,0 +1,33 @@ +preferences)) { + return $this->preferences[$key]; + } + + return null; + } + /** * @return string */ diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 915d544ec..ef732ec53 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -18,6 +18,7 @@ use Exception; use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Firefox\FirefoxDriver; +use Facebook\WebDriver\Firefox\FirefoxPreferences; use Facebook\WebDriver\Firefox\FirefoxProfile; use Facebook\WebDriver\WebDriverCapabilities; use Facebook\WebDriver\WebDriverPlatform; @@ -203,7 +204,7 @@ public static function firefox() { // disable the "Reader View" help tooltip, which can hide elements in the window.document $profile = new FirefoxProfile(); - $profile->setPreference('reader.parse-on-load.enabled', false); + $profile->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false); $caps->setCapability(FirefoxDriver::PROFILE, $profile); return $caps; From a0485d418a6841eaaec80b718676e8a8ed618a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 30 Dec 2015 19:23:23 +0100 Subject: [PATCH 015/600] Unit tests for WebDriverCommand and DesiredCapabilities --- tests/unit/Remote/DesiredCapabilitiesTest.php | 133 ++++++++++++++++++ tests/unit/Remote/WebDriverCommandTest.php | 28 ++++ 2 files changed, 161 insertions(+) create mode 100644 tests/unit/Remote/DesiredCapabilitiesTest.php create mode 100644 tests/unit/Remote/WebDriverCommandTest.php diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php new file mode 100644 index 000000000..7f187f706 --- /dev/null +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -0,0 +1,133 @@ + 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY) + ); + + $this->assertSame('fooVal', $capabilities->getCapability('fooKey')); + $this->assertSame('ANY', $capabilities->getPlatform()); + + $this->assertSame( + array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY), + $capabilities->toArray() + ); + } + + public function testShouldInstantiateEmptyInstance() + { + $capabilities = new DesiredCapabilities(); + + $this->assertNull($capabilities->getCapability('foo')); + $this->assertSame(array(), $capabilities->toArray()); + } + + public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() + { + $capabilities = new DesiredCapabilities(); + // generic capability setter + $capabilities->setCapability('custom', 1337); + // specific setters + $capabilities->setBrowserName(WebDriverBrowserType::CHROME); + $capabilities->setPlatform(WebDriverPlatform::LINUX); + $capabilities->setVersion(333); + + $this->assertSame(1337, $capabilities->getCapability('custom')); + $this->assertSame(WebDriverBrowserType::CHROME, $capabilities->getBrowserName()); + $this->assertSame(WebDriverPlatform::LINUX, $capabilities->getPlatform()); + $this->assertSame(333, $capabilities->getVersion()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage isJavascriptEnable() is a htmlunit-only option + */ + public function testShouldNotAllowToDisableJavascriptForNonHtmlUnitBrowser() + { + $capabilities = new DesiredCapabilities(); + $capabilities->setBrowserName(WebDriverBrowserType::FIREFOX); + $capabilities->setJavascriptEnabled(false); + } + + public function testShouldAllowToDisableJavascriptForHtmlUnitBrowser() + { + $capabilities = new DesiredCapabilities(); + $capabilities->setBrowserName(WebDriverBrowserType::HTMLUNIT); + $capabilities->setJavascriptEnabled(false); + + $this->assertFalse($capabilities->isJavascriptEnabled()); + } + + /** + * @dataProvider browserCapabilitiesProvider + * @param string $setupMethod + * @param string $expectedBrowser + * @param string $expectedPlatform + */ + public function testShouldProvideShortcutSetupForCapabilitiesOfEachBrowser( + $setupMethod, + $expectedBrowser, + $expectedPlatform + ) + { + /** @var DesiredCapabilities $capabilities */ + $capabilities = call_user_func(array('Facebook\WebDriver\Remote\DesiredCapabilities', $setupMethod)); + + $this->assertSame($expectedBrowser, $capabilities->getBrowserName()); + $this->assertSame($expectedPlatform, $capabilities->getPlatform()); + } + + /** + * @return array + */ + public function browserCapabilitiesProvider() + { + return array( + array('android', WebDriverBrowserType::ANDROID, WebDriverPlatform::ANDROID), + array('chrome', WebDriverBrowserType::CHROME, WebDriverPlatform::ANY), + array('firefox', WebDriverBrowserType::FIREFOX, WebDriverPlatform::ANY), + array('htmlUnit', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), + array('htmlUnitWithJS', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), + array('internetExplorer', WebDriverBrowserType::IE, WebDriverPlatform::WINDOWS), + array('iphone', WebDriverBrowserType::IPHONE, WebDriverPlatform::MAC), + array('ipad', WebDriverBrowserType::IPAD, WebDriverPlatform::MAC), + array('opera', WebDriverBrowserType::OPERA, WebDriverPlatform::ANY), + array('safari', WebDriverBrowserType::SAFARI, WebDriverPlatform::ANY), + array('phantomjs', WebDriverBrowserType::PHANTOMJS, WebDriverPlatform::ANY), + ); + } + + public function testShouldSetupFirefoxProfileAndDisableReaderViewForFirefoxBrowser() + { + $capabilities = DesiredCapabilities::firefox(); + + /** @var FirefoxProfile $firefoxProfile */ + $firefoxProfile = $capabilities->getCapability(FirefoxDriver::PROFILE); + $this->assertInstanceOf('Facebook\WebDriver\Firefox\FirefoxProfile', $firefoxProfile); + + $this->assertSame('false', $firefoxProfile->getPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED)); + } +} diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php new file mode 100644 index 000000000..b4b9fc052 --- /dev/null +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -0,0 +1,28 @@ + 'bar')); + + $this->assertSame('session-id-123', $command->getSessionID()); + $this->assertSame('bar-baz-name', $command->getName()); + $this->assertSame(array('foo' => 'bar'), $command->getParameters()); + } +} From a7fd742c06ffc594cac8ccbec539f1196dcfabc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 1 Jan 2016 17:06:12 +0100 Subject: [PATCH 016/600] Added CHANGELOG.md (fixes #275) --- CHANGELOG.md | 14 ++++++++++++++ README.md | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..2229754c1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog +This project versioning adheres to [Semantic Versioning](http://semver.org/). + +## Unreleased +- Added CHANGELOG.md + +## 1.1.1 - 2015-12-31 +- Fixed strict standards error in `ChromeDriver` +- Added unit tests for `WebDriverCommand` and `DesiredCapabilities` +- Fixed retrieving temporary path name in `FirefoxDriver` when `open_basedir` restriction is in effect + +## 1.1.0 - 2015-12-08 +- FirefoxProfile improved - added possibility to set RDF file and to add datas for extensions +- Fixed setting 0 second timeout of `WebDriverWait` diff --git a/README.md b/README.md index 7beb7564c..5f2b0a958 100644 --- a/README.md +++ b/README.md @@ -77,15 +77,10 @@ Install the library. RemoteWebDriver::create($host, $desired_capabilities); ``` -* See https://code.google.com/p/selenium/wiki/DesiredCapabilities for more details. +* See https://code.google.com/p/selenium/wiki/DesiredCapabilities for more details. -## RUN UNIT TESTS - -To run unit tests simply run: - - ./vendor/bin/phpunit -c ./tests - -Note: For the functional test suite, a running selenium server is required. +## Changelog +For latest changes see [CHANGELOG.md](CHANGELOG.md) file. ## MORE INFORMATION @@ -118,3 +113,11 @@ We love to have your help to make php-webdriver better. Feel free to When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. FYI, here is the overview of [the official Java API](http://selenium.googlecode.com/svn/trunk/docs/api/java/index.html?overview-summary.html) + +### Run unit tests + +To run unit tests simply run: + + ./vendor/bin/phpunit -c ./tests + +Note: For the functional test suite, a running selenium server is required. From f89848df63108c8938e2c1cc45addd0c6d56e718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 1 Jan 2016 17:21:26 +0100 Subject: [PATCH 017/600] Cleanup README a bit --- README.md | 66 ++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 5f2b0a958..cf25e6021 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,61 @@ -php-webdriver -- WebDriver bindings for PHP +php-webdriver – WebDriver bindings for PHP =========================================== -## DESCRIPTION +## Description +Php-webdriver library is PHP language binding for Selenium WebDriver, which allows you to control web browsers from PHP. -This WebDriver client aims to be as close as possible to bindings in other languages. The concepts are very similar to the Java, .NET, Python and Ruby bindings for WebDriver. +This WebDriver client aims to be as close as possible to bindings in other languages. +The concepts are very similar to the Java, .NET, Python and Ruby bindings for WebDriver. -Looking for documentation about php-webdriver? See http://facebook.github.io/php-webdriver/ +This is new version of PHP client, rewritten from scratch starting 2013. +Using the old version? Check out Adam Goucher's fork of it at https://github.com/Element-34/php-webdriver -The PHP client was rewritten from scratch. Using the old version? Check out Adam Goucher's fork of it at https://github.com/Element-34/php-webdriver +Looking for API documentation of php-webdriver? See http://facebook.github.io/php-webdriver/ Any complaint, question, idea? You can post it on the user group https://www.facebook.com/groups/phpwebdriver/. -## GETTING THE CODE +## Installation -There are two ways of getting the code: +Installation is possible using [Composer](https://getcomposer.org/). -### Via Github - git clone git@github.com:facebook/php-webdriver.git - -### Via Packagist -Add the dependency to composer.json (see https://packagist.org/packages/facebook/webdriver) - -```json -{ - "require": { - "facebook/webdriver": "~1.0" - } -} -``` - -## INSTALLATION - -Download the composer.phar +If you don't already use Composer, you can download the `composer.phar` binary: curl -sS https://getcomposer.org/installer | php -Install the library. - - php composer.phar install +Then install the library: + php composer.phar require facebook/webdriver -## GETTING STARTED +## Getting started -* All you need as the server for this client is the selenium-server-standalone-#.jar file provided here: http://selenium-release.storage.googleapis.com/index.html +All you need as the server for this client is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html -* Download and run that file, replacing # with the current server version. +* Download and run that file, replacing # with the current server version. ``` java -jar selenium-server-standalone-#.jar ``` -* Then when you create a session, be sure to pass the url to where your server is running. +Then when you create a session, be sure to pass the url to where your server is running. ```php // This would be the url of the host running the server-standalone.jar $host = 'http://localhost:4444/wd/hub'; // this is the default ``` -* Launch Firefox +* Launch Firefox: ```php $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); ``` -* Launch Chrome +* Launch Chrome: ```php $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); ``` -* You can also customize the desired capabilities. +You can also customize the desired capabilities: ```php $desired_capabilities = DesiredCapabilities::firefox(); @@ -82,13 +68,13 @@ Install the library. ## Changelog For latest changes see [CHANGELOG.md](CHANGELOG.md) file. -## MORE INFORMATION +## More information Check out the Selenium docs and wiki at http://docs.seleniumhq.org/docs/ and https://code.google.com/p/selenium/wiki Learn how to integrate it with PHPUnit [Blogpost](http://codeception.com/11-12-2013/working-with-phpunit-and-selenium-webdriver.html) | [Demo Project](https://github.com/DavertMik/php-webdriver-demo) -## SUPPORT +## Support We have a great community willing to try and help you! @@ -104,12 +90,12 @@ https://www.facebook.com/groups/phpwebdriver/ If you're reading this you've already found our Github repository. If you have a question, feel free to submit it as an issue and our staff will do their best to help you as soon as possible. -## CONTRIBUTING +## Contributing -We love to have your help to make php-webdriver better. Feel free to +We love to have your help to make php-webdriver better. Feel free to -* open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem. -* fork the project and submit [pull request](https://github.com/facebook/php-webdriver/pulls). Before the pull requests can be accepted, a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed. +* open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem. +* fork the project and submit [pull request](https://github.com/facebook/php-webdriver/pulls). Before the pull requests can be accepted, a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed. When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. FYI, here is the overview of [the official Java API](http://selenium.googlecode.com/svn/trunk/docs/api/java/index.html?overview-summary.html) From 5f55880ea3eb0d3820c0731c9e6a33f801e9f707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 1 Jan 2016 17:22:06 +0100 Subject: [PATCH 018/600] Fix not working example in README (setJavascriptEnabled works only for htmlUnit browser, not Firefox --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cf25e6021..42883b931 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,8 @@ You can also customize the desired capabilities: ```php $desired_capabilities = DesiredCapabilities::firefox(); - $desired_capabilities->setJavascriptEnabled(false); - RemoteWebDriver::create($host, $desired_capabilities); + $desired_capabilities->setCapability('acceptSslCerts', false); + $driver = RemoteWebDriver::create($host, $desired_capabilities); ``` * See https://code.google.com/p/selenium/wiki/DesiredCapabilities for more details. From 49127be66fde8657080e1d48c26051f06a3b1cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 4 Jan 2016 18:17:28 +0100 Subject: [PATCH 019/600] Added information and rules for contributors --- CHANGELOG.md | 1 + CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ README.md | 17 ++--------------- 3 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2229754c1..ff5496df5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - Added CHANGELOG.md +- Added CONTRIBUTING.md with information and rules for contributors ## 1.1.1 - 2015-12-31 - Fixed strict standards error in `ChromeDriver` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..1da3f3d35 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing to php-webdriver + +We love to have your help to make php-webdriver better! + +Feel free to open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem, or +send a pull request (see bellow) with your contribution. + +## Workflow when contributing a patch + +1. Fork the project on GitHub +2. Implement your code changes into separate branch +3. Make sure all PHPUnit tests passes (see below). We also have Travis CI build which will automatically run tests on your pull request). +4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md) +5. Submit your [pull request](https://github.com/facebook/php-webdriver/pulls) against community branch + +Note before any pull request can be accepted, a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed. + +When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. +FYI, here is the overview of [the official Java API](http://selenium.googlecode.com/svn/trunk/docs/api/java/index.html?overview-summary.html) + +### Run unit tests + +There are two test-suites: one with unit tests only, second with functional tests, which require running selenium server. + +To execute all tests simply run: + + ./vendor/bin/phpunit + +If you want to execute just the unit tests, run: + + ./vendor/bin/phpunit --testsuite Unit-Testsuite + +For the functional tests you must first download and start the selenium server, then run the `Functional-Testsuite` test suite: + + java -jar selenium-server-standalone-2.48.2.jar -log selenium.log & + ./vendor/bin/phpunit --testsuite Functional-Testsuite diff --git a/README.md b/README.md index 42883b931..a69a01f54 100644 --- a/README.md +++ b/README.md @@ -92,18 +92,5 @@ If you're reading this you've already found our Github repository. If you have a ## Contributing -We love to have your help to make php-webdriver better. Feel free to - -* open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem. -* fork the project and submit [pull request](https://github.com/facebook/php-webdriver/pulls). Before the pull requests can be accepted, a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed. - -When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. -FYI, here is the overview of [the official Java API](http://selenium.googlecode.com/svn/trunk/docs/api/java/index.html?overview-summary.html) - -### Run unit tests - -To run unit tests simply run: - - ./vendor/bin/phpunit -c ./tests - -Note: For the functional test suite, a running selenium server is required. +We love to have your help to make php-webdriver better. See [CONTRIBUTING.md](CONTRIBUTING.md) for more information +about contributing and developing php-webdriver. From bc48fe4584e9816e6a8f4f7a2b7ecfda091850d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 5 Jan 2016 08:36:56 +0100 Subject: [PATCH 020/600] Rename test suites to make them easier to write --- CONTRIBUTING.md | 6 +++--- phpunit.xml.dist | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1da3f3d35..b426d475d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,9 +28,9 @@ To execute all tests simply run: If you want to execute just the unit tests, run: - ./vendor/bin/phpunit --testsuite Unit-Testsuite + ./vendor/bin/phpunit --testsuite unit -For the functional tests you must first download and start the selenium server, then run the `Functional-Testsuite` test suite: +For the functional tests you must first download and start the selenium server, then run the `functional` test suite: java -jar selenium-server-standalone-2.48.2.jar -log selenium.log & - ./vendor/bin/phpunit --testsuite Functional-Testsuite + ./vendor/bin/phpunit --testsuite functional diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 83eb0ecef..06dee9c0f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,12 +15,12 @@ bootstrap="tests/bootstrap.php" > - - + + tests/unit - - tests/functional/ + + tests/functional From ebed69f8404ca5ca1ad4468b6bae9cb93e31a231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 6 Jan 2016 22:09:11 +0100 Subject: [PATCH 021/600] Fix code markdown in README --- README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a69a01f54..9f8d34d3d 100644 --- a/README.md +++ b/README.md @@ -30,18 +30,16 @@ Then install the library: All you need as the server for this client is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html -* Download and run that file, replacing # with the current server version. +Download and run that file, replacing # with the current server version. - ``` java -jar selenium-server-standalone-#.jar - ``` Then when you create a session, be sure to pass the url to where your server is running. - ```php - // This would be the url of the host running the server-standalone.jar - $host = 'http://localhost:4444/wd/hub'; // this is the default - ``` +```php +// This would be the url of the host running the server-standalone.jar +$host = 'http://localhost:4444/wd/hub'; // this is the default +``` * Launch Firefox: @@ -57,11 +55,11 @@ Then when you create a session, be sure to pass the url to where your server is You can also customize the desired capabilities: - ```php - $desired_capabilities = DesiredCapabilities::firefox(); - $desired_capabilities->setCapability('acceptSslCerts', false); - $driver = RemoteWebDriver::create($host, $desired_capabilities); - ``` +```php +$desired_capabilities = DesiredCapabilities::firefox(); +$desired_capabilities->setCapability('acceptSslCerts', false); +$driver = RemoteWebDriver::create($host, $desired_capabilities); +``` * See https://code.google.com/p/selenium/wiki/DesiredCapabilities for more details. From 017bf3bc88d3ae2cf5a8e98c8004bec1f2835927 Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Mon, 1 Feb 2016 13:17:53 +0100 Subject: [PATCH 022/600] [+]: fixed function-call from "$checker->waitUntilUnAvailable()" -> "$checker->waitUntilUnavailable()" [~]: "\t" -> spaces [~]: "dirname(__FILE__)" -> "__DIR__" [*]: "" -> --- lib/Firefox/FirefoxProfile.php | 21 ++++++++++++--------- lib/Remote/Service/DriverService.php | 2 +- tests/functional/WebDriverTestCase.php | 6 +++--- tests/functional/html/upload.html | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index bf23e5e7a..651e0b2eb 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -131,10 +131,10 @@ public function encode() { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($extension_datas, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST); foreach ($iterator as $item) { if ($item->isDir()) { - mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); - } else { - copy($item, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); - } + mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); + } else { + copy($item, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); + } } } @@ -150,15 +150,18 @@ public function encode() { $dir = new RecursiveDirectoryIterator($temp_dir); $files = new RecursiveIteratorIterator($dir); + + $dir_prefix = preg_replace( + '#\\\\#', + '\\\\\\\\', + $temp_dir.DIRECTORY_SEPARATOR + ); + foreach ($files as $name => $object) { if (is_dir($name)) { continue; } - $dir_prefix = preg_replace( - '#\\\\#', - '\\\\\\\\', - $temp_dir.DIRECTORY_SEPARATOR - ); + $path = preg_replace("#^{$dir_prefix}#", "", $name); $zip->addFile($name, $path); } diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index 09ad7c815..8a18e5d5d 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -109,7 +109,7 @@ public function stop() { $this->process = null; $checker = new URLChecker(); - $checker->waitUntilUnAvailable(3 * 1000, $this->url.'/shutdown'); + $checker->waitUntilUnavailable(3 * 1000, $this->url.'/shutdown'); return $this; } diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 73b3c2b58..9be2153d3 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -40,8 +40,8 @@ protected function setUp() { protected function tearDown() { if ($this->driver) { - $this->driver->quit(); - } + $this->driver->quit(); + } } /** @@ -51,6 +51,6 @@ protected function tearDown() { * @return string */ protected function getTestPath($path) { - return 'file:///'.dirname(__FILE__).'/html/'.$path; + return 'file:///'.__DIR__.'/html/'.$path; } } diff --git a/tests/functional/html/upload.html b/tests/functional/html/upload.html index d542ad04f..ed03702d3 100644 --- a/tests/functional/html/upload.html +++ b/tests/functional/html/upload.html @@ -4,7 +4,7 @@
- +
From 61274d2fa4b38162e7b25391321484fa8164da30 Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Mon, 1 Feb 2016 13:18:53 +0100 Subject: [PATCH 023/600] [+]: ".gitattributes" <- prevent installing special files via composer --- .gitattributes | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c3b6383af --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +* text=auto + +/tests export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/example.php export-ignore +/phpunit.xml.dist export-ignore From 0f3048f2499285538a8be240afa9d722aa6fe1d4 Mon Sep 17 00:00:00 2001 From: javier gomez Date: Thu, 25 Feb 2016 10:39:39 +0100 Subject: [PATCH 024/600] Enhance moveToElement method description --- lib/Interactions/WebDriverActions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Interactions/WebDriverActions.php b/lib/Interactions/WebDriverActions.php index 4d8a623d8..3e11b3c0a 100644 --- a/lib/Interactions/WebDriverActions.php +++ b/lib/Interactions/WebDriverActions.php @@ -168,8 +168,8 @@ public function moveByOffset($x_offset, $y_offset) { } /** - * Move to the middle of the given WebDriverElement. If offset are provided, - * move the an offset from the top-left cornerof that element. + * Move to the middle of the given WebDriverElement. + * Extra shift, calculated from the top-left corner of the element, can be set by passing $x_offset and $y_offset parameters. * * @param WebDriverElement $element * @param int $x_offset From 09ec61c59a8fd86bd02b9efa28748ccc2ba6444a Mon Sep 17 00:00:00 2001 From: phpdave Date: Tue, 15 Mar 2016 09:12:55 -0400 Subject: [PATCH 025/600] Updated Readme to fix DesiredCapabilities link Fixing this issue https://github.com/facebook/php-webdriver/issues/283 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f8d34d3d..146d45ad6 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ $desired_capabilities->setCapability('acceptSslCerts', false); $driver = RemoteWebDriver::create($host, $desired_capabilities); ``` -* See https://code.google.com/p/selenium/wiki/DesiredCapabilities for more details. +* See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities for more details. ## Changelog For latest changes see [CHANGELOG.md](CHANGELOG.md) file. From 46661a59a094469227c5b10c6e8716f71079ec03 Mon Sep 17 00:00:00 2001 From: Jan Kohlhof Date: Fri, 11 Mar 2016 22:55:45 +0100 Subject: [PATCH 026/600] Added ext-curl as dependency As suggested correctly in #279 --- CHANGELOG.md | 1 + composer.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff5496df5..103ffee19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- Added ext-curl to composer.json - Added CHANGELOG.md - Added CONTRIBUTING.md with information and rules for contributors diff --git a/composer.json b/composer.json index be4ba7dd5..682e72479 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "source": "https://github.com/facebook/php-webdriver" }, "require": { - "php": ">=5.3.19" + "php": ">=5.3.19", + "ext-curl": "*" }, "require-dev": { "phpunit/phpunit": "4.6.*" From a7834be0fed2770ca9b760b443c10267352a917e Mon Sep 17 00:00:00 2001 From: Scott Davey Date: Mon, 9 May 2016 17:30:24 +1000 Subject: [PATCH 027/600] Fixed PHP Fatal crash in RemoteWebDriver:507 --- lib/Remote/RemoteWebDriver.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 1fda245b2..8fb7003c1 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -504,7 +504,11 @@ public function execute($command_name, $params = array()) { $params ); - $response = $this->executor->execute($command); - return $response->getValue(); + if ($this->executor) { + $response = $this->executor->execute($command); + return $response->getValue(); + } else { + return null; + } } } From 0eb0a0ad8c7177a5071d17853c982ba2507d25f3 Mon Sep 17 00:00:00 2001 From: Andre Fortin Date: Fri, 3 Jun 2016 19:38:44 -0400 Subject: [PATCH 028/600] Throw exception if extension doesn't exist. Update to make extractTo() throw an exception if the Firefox extension .xpi file doesn't exist, which should be the desired behavior. Currently extractTo() only throws an error if the .xpi file exists AND is unable to open. ZipArchive throws some Warning messages when you use extractTo() and close() on an initialized ZipArchive object which is the case if the file doesn't exist. --- lib/Firefox/FirefoxProfile.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 651e0b2eb..9617f4e77 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -249,11 +249,15 @@ private function deleteDirectory($directory) { */ private function extractTo($xpi, $target_dir) { $zip = new ZipArchive(); - if ($zip->open($xpi)) { - $zip->extractTo($target_dir); - $zip->close(); + if (file_exists($xpi)) { + if ($zip->open($xpi)) { + $zip->extractTo($target_dir); + $zip->close(); + } else { + throw new \Exception("Failed to open the firefox extension. '$xpi'"); + } } else { - throw new \Exception("Failed to open the firefox extension. '$xpi'"); + throw new \Exception("Firefox extension doesn't exist. '$xpi'"); } return $this; } From 14a6ff7d8b7f8303c79ac5154a9da9041817c089 Mon Sep 17 00:00:00 2001 From: Andre Fortin Date: Sat, 4 Jun 2016 02:11:38 -0400 Subject: [PATCH 029/600] Fixed Hardcoded 'em' namespace in installExtension() prevents some extensions from loading:507 --- lib/Firefox/FirefoxProfile.php | 42 ++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 9617f4e77..03830dc63 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -183,21 +183,33 @@ public function encode() { */ private function installExtension($extension, $profile_dir) { $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfileExtension'); - - $this->extractTo($extension, $temp_dir); - - $install_rdf_path = $temp_dir.'/install.rdf'; - // This is a hacky way to parse the id since there is no offical - // RDF parser library. - $matches = array(); - $xml = file_get_contents($install_rdf_path); - preg_match('#([^<]+)#', $xml, $matches); - $ext_dir = $profile_dir.'/extensions/'.$matches[1]; - - mkdir($ext_dir, 0777, true); - - $this->extractTo($extension, $ext_dir); - + $this->extractTo($extension, $temp_dir); + + // This is a hacky way to parse the id since there is no offical RDF parser library. + // Find the correct namespace for the id element. + $install_rdf_path = $temp_dir.'/install.rdf'; + $xml = simplexml_load_file($install_rdf_path); + $ns = $xml->getDocNamespaces(); + $prefix = ''; + if (!empty($ns)) { + foreach($ns as $key => $value) { + if (strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) { + if ($key != '') { + $prefix = $key . ':'; // Separate the namespace from the name. + } + break; + } + } + } + // Get the extension id from the install manifest. + $matches = array(); + preg_match('#<'.$prefix.'id>([^<]+)#', $xml->asXML(), $matches); + if (isset($matches[1])) { + $ext_dir = $profile_dir.'/extensions/'.$matches[1]; + mkdir($ext_dir, 0777, true); + $this->extractTo($extension, $ext_dir); + } + // clean up $this->deleteDirectory($temp_dir); From 4dc9974e643a9330d6c614bcf2c4454c200f922a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 19 Jul 2016 02:09:35 +0200 Subject: [PATCH 030/600] Update changelog according to latest release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 103ffee19..02933ab90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file + +## 1.1.2 - 2016-06-04 - Added ext-curl to composer.json - Added CHANGELOG.md - Added CONTRIBUTING.md with information and rules for contributors From 29a41cb8e7f590ffdc613dab9a28ebafd5af5c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 30 Jul 2016 14:55:20 +0200 Subject: [PATCH 031/600] Allow PHPUnit 5.x for unit tests --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 682e72479..43c61fa88 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "ext-curl": "*" }, "require-dev": { - "phpunit/phpunit": "4.6.*" + "phpunit/phpunit": "4.6.* || ~5.0" }, "suggest": { "phpdocumentor/phpdocumentor": "2.*" From 1f158a0091db69ee82d1e1be604fbee15d230537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 30 Jul 2016 14:55:34 +0200 Subject: [PATCH 032/600] Replace deprecated ->getMock() call --- .../Internal/WebDriverButtonReleaseActionTest.php | 4 ++-- .../unit/Interactions/Internal/WebDriverClickActionTest.php | 4 ++-- .../Internal/WebDriverClickAndHoldActionTest.php | 4 ++-- .../Internal/WebDriverContextClickActionTest.php | 4 ++-- .../Internal/WebDriverDoubleClickActionTest.php | 4 ++-- .../Interactions/Internal/WebDriverKeyDownActionTest.php | 6 +++--- .../unit/Interactions/Internal/WebDriverKeyUpActionTest.php | 6 +++--- .../Interactions/Internal/WebDriverMouseMoveActionTest.php | 4 ++-- .../Internal/WebDriverMouseToOffsetActionTest.php | 4 ++-- .../Interactions/Internal/WebDriverSendKeysActionTest.php | 6 +++--- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php index 982e8d268..58373d9b9 100644 --- a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php @@ -27,8 +27,8 @@ class WebDriverButtonReleaseActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverButtonReleaseAction = new WebDriverButtonReleaseAction( $this->webDriverMouse, $this->locationProvider diff --git a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php index 8fab683fe..c58d507d1 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php @@ -27,8 +27,8 @@ class WebDriverClickActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverClickAction = new WebDriverClickAction( $this->webDriverMouse, $this->locationProvider diff --git a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php index b10ac2cea..ae046c58e 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php @@ -27,8 +27,8 @@ class WebDriverClickAndHoldActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverClickAndHoldAction = new WebDriverClickAndHoldAction( $this->webDriverMouse, $this->locationProvider diff --git a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php index a57cb127a..d9b9ef2b8 100644 --- a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php @@ -27,8 +27,8 @@ class WebDriverContextClickActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverContextClickAction = new WebDriverContextClickAction( $this->webDriverMouse, $this->locationProvider diff --git a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php index 7f09f64dc..f1c6d3a02 100644 --- a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php @@ -27,8 +27,8 @@ class WebDriverDoubleClickActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverDoubleClickAction = new WebDriverDoubleClickAction( $this->webDriverMouse, $this->locationProvider diff --git a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php index 5bba82f4f..10a6201e0 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php @@ -30,9 +30,9 @@ class WebDriverKeyDownActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverKeyboard = $this->getMock('Facebook\WebDriver\WebDriverKeyboard'); - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverKeyDownAction = new WebDriverKeyDownAction( $this->webDriverKeyboard, diff --git a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php index cd2b7b00c..75fb1bde9 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php @@ -30,9 +30,9 @@ class WebDriverKeyUpActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverKeyboard = $this->getMock('Facebook\WebDriver\WebDriverKeyboard'); - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverKeyUpAction = new WebDriverKeyUpAction( $this->webDriverKeyboard, diff --git a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php index 6376adfa0..10edb2588 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php @@ -27,8 +27,8 @@ class WebDriverMouseMoveActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverMouseMoveAction = new WebDriverMouseMoveAction( $this->webDriverMouse, diff --git a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php index 2ea16d552..aeec43a5a 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php @@ -29,8 +29,8 @@ class WebDriverMouseToOffsetActionTest extends \PHPUnit_Framework_TestCase { private $locationProvider; public function setUp() { - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->webDriverMoveToOffsetAction = new WebDriverMoveToOffsetAction( $this->webDriverMouse, diff --git a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php index f7c2917d0..bf1a5b8a7 100644 --- a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php @@ -32,9 +32,9 @@ class WebDriverSendKeysActionTest extends \PHPUnit_Framework_TestCase { private $keys; public function setUp() { - $this->webDriverKeyboard = $this->getMock('Facebook\WebDriver\WebDriverKeyboard'); - $this->webDriverMouse = $this->getMock('Facebook\WebDriver\WebDriverMouse'); - $this->locationProvider = $this->getMock('Facebook\WebDriver\Internal\WebDriverLocatable'); + $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); $this->keys = array('t', 'e', 's', 't'); $this->webDriverSendKeysAction = new WebDriverSendKeysAction( From c051b545cbd566f87d05ce99a5bcfad2e5e0ae28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 30 Jul 2016 16:16:16 +0200 Subject: [PATCH 033/600] PSR-2 codestyle --- CHANGELOG.md | 1 + lib/Chrome/ChromeDriver.php | 116 +- lib/Chrome/ChromeDriverService.php | 23 +- lib/Chrome/ChromeOptions.php | 275 ++--- .../ElementNotSelectableException.php | 7 +- lib/Exception/ElementNotVisibleException.php | 6 +- lib/Exception/ExpectedException.php | 7 +- .../IMEEngineActivationFailedException.php | 7 +- lib/Exception/IMENotAvailableException.php | 7 +- lib/Exception/IndexOutOfBoundsException.php | 6 +- .../InvalidCookieDomainException.php | 6 +- lib/Exception/InvalidCoordinatesException.php | 7 +- .../InvalidElementStateException.php | 6 +- lib/Exception/InvalidSelectorException.php | 7 +- .../MoveTargetOutOfBoundsException.php | 7 +- lib/Exception/NoAlertOpenException.php | 6 +- lib/Exception/NoCollectionException.php | 6 +- lib/Exception/NoScriptResultException.php | 6 +- lib/Exception/NoStringException.php | 6 +- lib/Exception/NoStringLengthException.php | 6 +- lib/Exception/NoStringWrapperException.php | 6 +- lib/Exception/NoSuchCollectionException.php | 6 +- lib/Exception/NoSuchDocumentException.php | 7 +- lib/Exception/NoSuchDriverException.php | 6 +- lib/Exception/NoSuchElementException.php | 6 +- lib/Exception/NoSuchFrameException.php | 6 +- lib/Exception/NoSuchWindowException.php | 6 +- lib/Exception/NullPointerException.php | 7 +- lib/Exception/ScriptTimeoutException.php | 7 +- lib/Exception/SessionNotCreatedException.php | 7 +- .../StaleElementReferenceException.php | 6 +- lib/Exception/TimeOutException.php | 6 +- lib/Exception/UnableToSetCookieException.php | 6 +- .../UnexpectedAlertOpenException.php | 6 +- .../UnexpectedJavascriptException.php | 6 +- lib/Exception/UnexpectedTagNameException.php | 36 +- lib/Exception/UnknownCommandException.php | 6 +- lib/Exception/UnknownServerException.php | 6 +- .../UnrecognizedExceptionException.php | 7 +- .../UnsupportedOperationException.php | 7 +- lib/Exception/WebDriverCurlException.php | 7 +- lib/Exception/WebDriverException.php | 285 ++--- lib/Exception/XPathLookupException.php | 6 +- lib/Firefox/FirefoxDriver.php | 11 +- lib/Firefox/FirefoxPreferences.php | 21 +- lib/Firefox/FirefoxProfile.php | 479 +++++---- .../Internal/WebDriverButtonReleaseAction.php | 13 +- .../Internal/WebDriverClickAction.php | 13 +- .../Internal/WebDriverClickAndHoldAction.php | 13 +- .../Internal/WebDriverContextClickAction.php | 13 +- .../Internal/WebDriverCoordinates.php | 89 +- .../Internal/WebDriverDoubleClickAction.php | 13 +- .../Internal/WebDriverKeyDownAction.php | 15 +- .../Internal/WebDriverKeyUpAction.php | 15 +- .../Internal/WebDriverKeysRelatedAction.php | 51 +- .../Internal/WebDriverMouseAction.php | 63 +- .../Internal/WebDriverMouseMoveAction.php | 13 +- .../Internal/WebDriverMoveToOffsetAction.php | 44 +- .../Internal/WebDriverSendKeysAction.php | 48 +- .../Internal/WebDriverSingleKeyAction.php | 27 +- .../Touch/WebDriverDoubleTapAction.php | 13 +- .../Touch/WebDriverDownAction.php | 38 +- .../Touch/WebDriverFlickAction.php | 34 +- .../Touch/WebDriverFlickFromElementAction.php | 64 +- .../Touch/WebDriverLongPressAction.php | 13 +- .../Touch/WebDriverMoveAction.php | 38 +- .../Touch/WebDriverScrollAction.php | 38 +- .../WebDriverScrollFromElementAction.php | 54 +- lib/Interactions/Touch/WebDriverTapAction.php | 13 +- .../Touch/WebDriverTouchAction.php | 65 +- .../Touch/WebDriverTouchScreen.php | 185 ++-- lib/Interactions/WebDriverActions.php | 473 +++++---- lib/Interactions/WebDriverCompositeAction.php | 58 +- lib/Interactions/WebDriverTouchActions.php | 304 +++--- lib/Internal/WebDriverLocatable.php | 14 +- lib/JavaScriptExecutor.php | 53 +- lib/Net/URLChecker.php | 102 +- lib/Remote/DesiredCapabilities.php | 557 +++++----- lib/Remote/DriverCommand.php | 275 +++-- lib/Remote/ExecuteMethod.php | 16 +- lib/Remote/FileDetector.php | 22 +- lib/Remote/HttpCommandExecutor.php | 564 +++++----- lib/Remote/LocalFileDetector.php | 15 +- lib/Remote/RemoteExecuteMethod.php | 39 +- lib/Remote/RemoteKeyboard.php | 105 +- lib/Remote/RemoteMouse.php | 218 ++-- lib/Remote/RemoteTargetLocator.php | 147 +-- lib/Remote/RemoteTouchScreen.php | 350 +++--- lib/Remote/RemoteWebDriver.php | 994 +++++++++--------- lib/Remote/RemoteWebElement.php | 806 +++++++------- lib/Remote/Service/DriverCommandExecutor.php | 68 +- lib/Remote/Service/DriverService.php | 230 ++-- lib/Remote/UselessFileDetector.php | 18 +- lib/Remote/WebDriverBrowserType.php | 52 +- lib/Remote/WebDriverCapabilityType.php | 41 +- lib/Remote/WebDriverCommand.php | 75 +- lib/Remote/WebDriverResponse.php | 130 +-- lib/Support/Events/EventFiringWebDriver.php | 646 ++++++------ .../Events/EventFiringWebDriverNavigation.php | 267 ++--- lib/Support/Events/EventFiringWebElement.php | 662 ++++++------ lib/WebDriver.php | 229 ++-- lib/WebDriverAction.php | 11 +- lib/WebDriverAlert.php | 95 +- lib/WebDriverBy.php | 199 ++-- lib/WebDriverCapabilities.php | 66 +- lib/WebDriverCommandExecutor.php | 16 +- lib/WebDriverDimension.php | 72 +- lib/WebDriverDispatcher.php | 117 ++- lib/WebDriverElement.php | 230 ++-- lib/WebDriverEventListener.php | 191 ++-- lib/WebDriverExpectedCondition.php | 801 +++++++------- lib/WebDriverHasInputDevices.php | 20 +- lib/WebDriverKeyboard.php | 50 +- lib/WebDriverKeys.php | 176 ++-- lib/WebDriverMouse.php | 74 +- lib/WebDriverNavigation.php | 95 +- lib/WebDriverOptions.php | 300 +++--- lib/WebDriverPlatform.php | 25 +- lib/WebDriverPoint.php | 121 ++- lib/WebDriverSearchContext.php | 42 +- lib/WebDriverSelect.php | 486 ++++----- lib/WebDriverTargetLocator.php | 78 +- lib/WebDriverTimeouts.php | 101 +- lib/WebDriverUpAction.php | 38 +- lib/WebDriverWait.php | 91 +- lib/WebDriverWindow.php | 248 ++--- tests/functional/BaseTest.php | 156 +-- tests/functional/FileUploadTest.php | 45 +- tests/functional/WebDriverTestCase.php | 57 +- .../WebDriverButtonReleaseActionTest.php | 47 +- .../Internal/WebDriverClickActionTest.php | 47 +- .../WebDriverClickAndHoldActionTest.php | 47 +- .../WebDriverContextClickActionTest.php | 47 +- .../Internal/WebDriverCoordinatesTest.php | 40 +- .../WebDriverDoubleClickActionTest.php | 47 +- .../Internal/WebDriverKeyDownActionTest.php | 57 +- .../Internal/WebDriverKeyUpActionTest.php | 59 +- .../Internal/WebDriverMouseMoveActionTest.php | 47 +- .../WebDriverMouseToOffsetActionTest.php | 55 +- .../Internal/WebDriverSendKeysActionTest.php | 65 +- tests/unit/Remote/DesiredCapabilitiesTest.php | 215 ++-- tests/unit/Remote/WebDriverCommandTest.php | 14 +- 142 files changed, 7637 insertions(+), 7149 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02933ab90..f379bdaa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file +- Comply codestyle with [PSR-2](http://www.php-fig.org/psr/psr-2/) ## 1.1.2 - 2016-06-04 - Added ext-curl to composer.json diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 0cabccd91..75131c215 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -15,72 +15,72 @@ namespace Facebook\WebDriver\Chrome; +use Facebook\WebDriver\Exception\WebDriverException; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\DriverCommand; -use Facebook\WebDriver\Remote\Service\DriverCommandExecutor; -use Facebook\WebDriver\Exception\WebDriverException; use Facebook\WebDriver\Remote\RemoteWebDriver; +use Facebook\WebDriver\Remote\Service\DriverCommandExecutor; use Facebook\WebDriver\Remote\WebDriverCommand; -class ChromeDriver extends RemoteWebDriver { +class ChromeDriver extends RemoteWebDriver +{ + public static function start(DesiredCapabilities $desired_capabilities = null, ChromeDriverService $service = null) + { + if ($desired_capabilities === null) { + $desired_capabilities = DesiredCapabilities::chrome(); + } + if ($service === null) { + $service = ChromeDriverService::createDefaultService(); + } + $executor = new DriverCommandExecutor($service); + $driver = new static(); + $driver->setCommandExecutor($executor) + ->startSession($desired_capabilities); - public static function start( - DesiredCapabilities $desired_capabilities = null, - ChromeDriverService $service = null - ) { - if ($desired_capabilities === null) { - $desired_capabilities = DesiredCapabilities::chrome(); + return $driver; } - if ($service === null) { - $service = ChromeDriverService::createDefaultService(); - } - $executor = new DriverCommandExecutor($service); - $driver = new static(); - $driver->setCommandExecutor($executor) - ->startSession($desired_capabilities); - return $driver; - } - public function startSession($desired_capabilities) { - $command = new WebDriverCommand( - null, - DriverCommand::NEW_SESSION, - array( - 'desiredCapabilities' => $desired_capabilities->toArray(), - ) - ); - $response = $this->executor->execute($command); - $this->setSessionID($response->getSessionID()); - } + public function startSession($desired_capabilities) + { + $command = new WebDriverCommand( + null, + DriverCommand::NEW_SESSION, + array( + 'desiredCapabilities' => $desired_capabilities->toArray(), + ) + ); + $response = $this->executor->execute($command); + $this->setSessionID($response->getSessionID()); + } - /** - * Always throws an exception. Use ChromeDriver::start() instead. - * - * @throws WebDriverException - */ - public static function create( - $url = 'http://localhost:4444/wd/hub', - $desired_capabilities = null, - $connection_timeout_in_ms = null, - $request_timeout_in_ms = null, - $http_proxy = null, - $http_proxy_port = null - ) { - throw new WebDriverException('Please use ChromeDriver::start() instead.'); - } + /** + * Always throws an exception. Use ChromeDriver::start() instead. + * + * @throws WebDriverException + */ + public static function create( + $url = 'http://localhost:4444/wd/hub', + $desired_capabilities = null, + $connection_timeout_in_ms = null, + $request_timeout_in_ms = null, + $http_proxy = null, + $http_proxy_port = null + ) { + throw new WebDriverException('Please use ChromeDriver::start() instead.'); + } - /** - * Always throws an exception. Use ChromeDriver::start() instead. - * - * @param string $session_id The existing session id - * @param string $url The url of the remote server - * - * @throws WebDriverException - */ - public static function createBySessionID( - $session_id, - $url = 'http://localhost:4444/wd/hub' - ) { - throw new WebDriverException('Please use ChromeDriver::start() instead.'); - } + /** + * Always throws an exception. Use ChromeDriver::start() instead. + * + * @param string $session_id The existing session id + * @param string $url The url of the remote server + * + * @throws WebDriverException + */ + public static function createBySessionID( + $session_id, + $url = 'http://localhost:4444/wd/hub' + ) { + throw new WebDriverException('Please use ChromeDriver::start() instead.'); + } } diff --git a/lib/Chrome/ChromeDriverService.php b/lib/Chrome/ChromeDriverService.php index d60f376a6..a48207a46 100644 --- a/lib/Chrome/ChromeDriverService.php +++ b/lib/Chrome/ChromeDriverService.php @@ -17,17 +17,18 @@ use Facebook\WebDriver\Remote\Service\DriverService; -class ChromeDriverService extends DriverService { +class ChromeDriverService extends DriverService +{ + // The environment variable storing the path to the chrome driver executable. + const CHROME_DRIVER_EXE_PROPERTY = 'webdriver.chrome.driver'; - // The environment variable storing the path to the chrome driver executable. - const CHROME_DRIVER_EXE_PROPERTY = "webdriver.chrome.driver"; - - public static function createDefaultService() { - $exe = getenv(self::CHROME_DRIVER_EXE_PROPERTY); - $port = 9515; // TODO: Get another port if the default port is used. - $args = array("--port=$port"); - $service = new ChromeDriverService($exe, $port, $args); - return $service; - } + public static function createDefaultService() + { + $exe = getenv(self::CHROME_DRIVER_EXE_PROPERTY); + $port = 9515; // TODO: Get another port if the default port is used. + $args = array("--port=$port"); + $service = new self($exe, $port, $args); + return $service; + } } diff --git a/lib/Chrome/ChromeOptions.php b/lib/Chrome/ChromeOptions.php index da387c55a..3af14b9c3 100644 --- a/lib/Chrome/ChromeOptions.php +++ b/lib/Chrome/ChromeOptions.php @@ -22,141 +22,154 @@ * * @see https://sites.google.com/a/chromium.org/chromedriver/capabilities */ -class ChromeOptions { - - /** - * The key of chrome options in desired capabilities. - */ - const CAPABILITY = "chromeOptions"; - - /** - * @var array - */ - private $arguments = array(); - - /** - * @var string - */ - private $binary = ''; - - /** - * @var array - */ - private $extensions = array(); - - /** - * @var array - */ - private $experimentalOptions = array(); - - /** - * Sets the path of the Chrome executable. The path should be either absolute - * or relative to the location running ChromeDriver server. - * - * @param string $path - * @return ChromeOptions - */ - public function setBinary($path) { - $this->binary = $path; - return $this; - } - - /** - * @param array $arguments - * @return ChromeOptions - */ - public function addArguments(array $arguments) { - $this->arguments = array_merge($this->arguments, $arguments); - return $this; - } - - /** - * Add a Chrome extension to install on browser startup. Each path should be - * a packed Chrome extension. - * - * @param array $paths - * @return ChromeOptions - */ - public function addExtensions(array $paths) { - foreach ($paths as $path) { - $this->addExtension($path); +class ChromeOptions +{ + /** + * The key of chrome options in desired capabilities. + */ + const CAPABILITY = 'chromeOptions'; + /** + * @var array + */ + private $arguments = array(); + /** + * @var string + */ + private $binary = ''; + /** + * @var array + */ + private $extensions = array(); + /** + * @var array + */ + private $experimentalOptions = array(); + + /** + * Sets the path of the Chrome executable. The path should be either absolute + * or relative to the location running ChromeDriver server. + * + * @param string $path + * @return ChromeOptions + */ + public function setBinary($path) + { + $this->binary = $path; + + return $this; } - return $this; - } - - /** - * @param array $encoded_extensions An array of base64 encoded of the extensions. - * @return ChromeOptions - */ - public function addEncodedExtensions(array $encoded_extensions) { - foreach ($encoded_extensions as $encoded_extension) { - $this->addEncodedExtension($encoded_extension); + + /** + * @param array $arguments + * @return ChromeOptions + */ + public function addArguments(array $arguments) + { + $this->arguments = array_merge($this->arguments, $arguments); + + return $this; + } + + /** + * Add a Chrome extension to install on browser startup. Each path should be + * a packed Chrome extension. + * + * @param array $paths + * @return ChromeOptions + */ + public function addExtensions(array $paths) + { + foreach ($paths as $path) { + $this->addExtension($path); + } + + return $this; + } + + /** + * @param array $encoded_extensions An array of base64 encoded of the extensions. + * @return ChromeOptions + */ + public function addEncodedExtensions(array $encoded_extensions) + { + foreach ($encoded_extensions as $encoded_extension) { + $this->addEncodedExtension($encoded_extension); + } + + return $this; + } + + /** + * Sets an experimental option which has not exposed officially. + * + * @param string $name + * @param mixed $value + * @return ChromeOptions + */ + public function setExperimentalOption($name, $value) + { + $this->experimentalOptions[$name] = $value; + + return $this; + } + + /** + * @return DesiredCapabilities The DesiredCapabilities for Chrome with this options. + */ + public function toCapabilities() + { + $capabilities = DesiredCapabilities::chrome(); + $capabilities->setCapability(self::CAPABILITY, $this); + + return $capabilities; } - return $this; - } - - /** - * Sets an experimental option which has not exposed officially. - * - * @param string $name - * @param mixed $value - * @return ChromeOptions - */ - public function setExperimentalOption($name, $value) { - $this->experimentalOptions[$name] = $value; - return $this; - } - - /** - * @return DesiredCapabilities The DesiredCapabilities for Chrome with this options. - */ - public function toCapabilities() { - $capabilities = DesiredCapabilities::chrome(); - $capabilities->setCapability(self::CAPABILITY, $this); - return $capabilities; - } - - /** - * @return array - */ - public function toArray() { - $options = $this->experimentalOptions; - - // The selenium server expects a 'dictionary' instead of a 'list' when - // reading the chrome option. However, an empty array in PHP will be - // converted to a 'list' instead of a 'dictionary'. To fix it, we always - // set the 'binary' to avoid returning an empty array. - $options['binary'] = $this->binary; - - if ($this->arguments) { - $options['args'] = $this->arguments; + + /** + * @return array + */ + public function toArray() + { + $options = $this->experimentalOptions; + + // The selenium server expects a 'dictionary' instead of a 'list' when + // reading the chrome option. However, an empty array in PHP will be + // converted to a 'list' instead of a 'dictionary'. To fix it, we always + // set the 'binary' to avoid returning an empty array. + $options['binary'] = $this->binary; + + if ($this->arguments) { + $options['args'] = $this->arguments; + } + + if ($this->extensions) { + $options['extensions'] = $this->extensions; + } + + return $options; } - if ($this->extensions) { - $options['extensions'] = $this->extensions; + /** + * Add a Chrome extension to install on browser startup. Each path should be a + * packed Chrome extension. + * + * @param string $path + * @return ChromeOptions + */ + private function addExtension($path) + { + $this->addEncodedExtension(base64_encode(file_get_contents($path))); + + return $this; } - return $options; - } - - /** - * Add a Chrome extension to install on browser startup. Each path should be a - * packed Chrome extension. - * - * @param string $path - * @return ChromeOptions - */ - private function addExtension($path) { - $this->addEncodedExtension(base64_encode(file_get_contents($path))); - return $this; - } - - /** - * @param string $encoded_extension Base64 encoded of the extension. - * @return ChromeOptions - */ - private function addEncodedExtension($encoded_extension) { - $this->extensions[] = $encoded_extension; - return $this; - } + /** + * @param string $encoded_extension Base64 encoded of the extension. + * @return ChromeOptions + */ + private function addEncodedExtension($encoded_extension) + { + $this->extensions[] = $encoded_extension; + + return $this; + } } diff --git a/lib/Exception/ElementNotSelectableException.php b/lib/Exception/ElementNotSelectableException.php index 9acfb88f2..77c6accb0 100644 --- a/lib/Exception/ElementNotSelectableException.php +++ b/lib/Exception/ElementNotSelectableException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class ElementNotSelectableException extends WebDriverException { - -} \ No newline at end of file +class ElementNotSelectableException extends WebDriverException +{ +} diff --git a/lib/Exception/ElementNotVisibleException.php b/lib/Exception/ElementNotVisibleException.php index c452d2daa..2de5fd10c 100644 --- a/lib/Exception/ElementNotVisibleException.php +++ b/lib/Exception/ElementNotVisibleException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class ElementNotVisibleException extends WebDriverException { - -} \ No newline at end of file +class ElementNotVisibleException extends WebDriverException +{ +} diff --git a/lib/Exception/ExpectedException.php b/lib/Exception/ExpectedException.php index cd8f15cc5..9c43f47e3 100644 --- a/lib/Exception/ExpectedException.php +++ b/lib/Exception/ExpectedException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class ExpectedException extends WebDriverException { - -} \ No newline at end of file +class ExpectedException extends WebDriverException +{ +} diff --git a/lib/Exception/IMEEngineActivationFailedException.php b/lib/Exception/IMEEngineActivationFailedException.php index cd13d0181..6e372c313 100644 --- a/lib/Exception/IMEEngineActivationFailedException.php +++ b/lib/Exception/IMEEngineActivationFailedException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class IMEEngineActivationFailedException extends WebDriverException { - -} \ No newline at end of file +class IMEEngineActivationFailedException extends WebDriverException +{ +} diff --git a/lib/Exception/IMENotAvailableException.php b/lib/Exception/IMENotAvailableException.php index 94497c0d5..aeb78dc48 100644 --- a/lib/Exception/IMENotAvailableException.php +++ b/lib/Exception/IMENotAvailableException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class IMENotAvailableException extends WebDriverException { - -} \ No newline at end of file +class IMENotAvailableException extends WebDriverException +{ +} diff --git a/lib/Exception/IndexOutOfBoundsException.php b/lib/Exception/IndexOutOfBoundsException.php index 322f67b14..ad52d21e9 100644 --- a/lib/Exception/IndexOutOfBoundsException.php +++ b/lib/Exception/IndexOutOfBoundsException.php @@ -2,6 +2,6 @@ namespace Facebook\WebDriver\Exception; -class IndexOutOfBoundsException extends WebDriverException { - -} \ No newline at end of file +class IndexOutOfBoundsException extends WebDriverException +{ +} diff --git a/lib/Exception/InvalidCookieDomainException.php b/lib/Exception/InvalidCookieDomainException.php index 5dbaae9eb..bae6c06db 100644 --- a/lib/Exception/InvalidCookieDomainException.php +++ b/lib/Exception/InvalidCookieDomainException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class InvalidCookieDomainException extends WebDriverException { - -} \ No newline at end of file +class InvalidCookieDomainException extends WebDriverException +{ +} diff --git a/lib/Exception/InvalidCoordinatesException.php b/lib/Exception/InvalidCoordinatesException.php index 571a107b2..53e9e9ef9 100644 --- a/lib/Exception/InvalidCoordinatesException.php +++ b/lib/Exception/InvalidCoordinatesException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class InvalidCoordinatesException extends WebDriverException { - -} \ No newline at end of file +class InvalidCoordinatesException extends WebDriverException +{ +} diff --git a/lib/Exception/InvalidElementStateException.php b/lib/Exception/InvalidElementStateException.php index 5c49c4c88..94ec58f1a 100644 --- a/lib/Exception/InvalidElementStateException.php +++ b/lib/Exception/InvalidElementStateException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class InvalidElementStateException extends WebDriverException { - -} \ No newline at end of file +class InvalidElementStateException extends WebDriverException +{ +} diff --git a/lib/Exception/InvalidSelectorException.php b/lib/Exception/InvalidSelectorException.php index 2c106970c..530fba2f4 100644 --- a/lib/Exception/InvalidSelectorException.php +++ b/lib/Exception/InvalidSelectorException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class InvalidSelectorException extends WebDriverException { - -} \ No newline at end of file +class InvalidSelectorException extends WebDriverException +{ +} diff --git a/lib/Exception/MoveTargetOutOfBoundsException.php b/lib/Exception/MoveTargetOutOfBoundsException.php index 39e97adbd..7a96b5805 100644 --- a/lib/Exception/MoveTargetOutOfBoundsException.php +++ b/lib/Exception/MoveTargetOutOfBoundsException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class MoveTargetOutOfBoundsException extends WebDriverException { - -} \ No newline at end of file +class MoveTargetOutOfBoundsException extends WebDriverException +{ +} diff --git a/lib/Exception/NoAlertOpenException.php b/lib/Exception/NoAlertOpenException.php index cdc846e08..ebc19964e 100644 --- a/lib/Exception/NoAlertOpenException.php +++ b/lib/Exception/NoAlertOpenException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoAlertOpenException extends WebDriverException { - -} \ No newline at end of file +class NoAlertOpenException extends WebDriverException +{ +} diff --git a/lib/Exception/NoCollectionException.php b/lib/Exception/NoCollectionException.php index 2bfe9069a..ec6335cdb 100644 --- a/lib/Exception/NoCollectionException.php +++ b/lib/Exception/NoCollectionException.php @@ -2,6 +2,6 @@ namespace Facebook\WebDriver\Exception; -class NoCollectionException extends WebDriverException { - -} \ No newline at end of file +class NoCollectionException extends WebDriverException +{ +} diff --git a/lib/Exception/NoScriptResultException.php b/lib/Exception/NoScriptResultException.php index 80d23f7de..f86ca2215 100644 --- a/lib/Exception/NoScriptResultException.php +++ b/lib/Exception/NoScriptResultException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoScriptResultException extends WebDriverException { - -} \ No newline at end of file +class NoScriptResultException extends WebDriverException +{ +} diff --git a/lib/Exception/NoStringException.php b/lib/Exception/NoStringException.php index 13c107b7d..790898607 100644 --- a/lib/Exception/NoStringException.php +++ b/lib/Exception/NoStringException.php @@ -2,6 +2,6 @@ namespace Facebook\WebDriver\Exception; -class NoStringException extends WebDriverException { - -} \ No newline at end of file +class NoStringException extends WebDriverException +{ +} diff --git a/lib/Exception/NoStringLengthException.php b/lib/Exception/NoStringLengthException.php index 8f50bb4ca..7047d72d3 100644 --- a/lib/Exception/NoStringLengthException.php +++ b/lib/Exception/NoStringLengthException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoStringLengthException extends WebDriverException { - -} \ No newline at end of file +class NoStringLengthException extends WebDriverException +{ +} diff --git a/lib/Exception/NoStringWrapperException.php b/lib/Exception/NoStringWrapperException.php index 2e17124e2..d5f75efd0 100644 --- a/lib/Exception/NoStringWrapperException.php +++ b/lib/Exception/NoStringWrapperException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoStringWrapperException extends WebDriverException { - -} \ No newline at end of file +class NoStringWrapperException extends WebDriverException +{ +} diff --git a/lib/Exception/NoSuchCollectionException.php b/lib/Exception/NoSuchCollectionException.php index d9e6c47ab..9899cf2fe 100644 --- a/lib/Exception/NoSuchCollectionException.php +++ b/lib/Exception/NoSuchCollectionException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoSuchCollectionException extends WebDriverException { - -} \ No newline at end of file +class NoSuchCollectionException extends WebDriverException +{ +} diff --git a/lib/Exception/NoSuchDocumentException.php b/lib/Exception/NoSuchDocumentException.php index b542fdfd6..f3bba91fd 100644 --- a/lib/Exception/NoSuchDocumentException.php +++ b/lib/Exception/NoSuchDocumentException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class NoSuchDocumentException extends WebDriverException { - -} \ No newline at end of file +class NoSuchDocumentException extends WebDriverException +{ +} diff --git a/lib/Exception/NoSuchDriverException.php b/lib/Exception/NoSuchDriverException.php index c34735b9d..c227d676a 100644 --- a/lib/Exception/NoSuchDriverException.php +++ b/lib/Exception/NoSuchDriverException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoSuchDriverException extends WebDriverException { - -} \ No newline at end of file +class NoSuchDriverException extends WebDriverException +{ +} diff --git a/lib/Exception/NoSuchElementException.php b/lib/Exception/NoSuchElementException.php index da39f7cab..f8d730580 100644 --- a/lib/Exception/NoSuchElementException.php +++ b/lib/Exception/NoSuchElementException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoSuchElementException extends WebDriverException { - -} \ No newline at end of file +class NoSuchElementException extends WebDriverException +{ +} diff --git a/lib/Exception/NoSuchFrameException.php b/lib/Exception/NoSuchFrameException.php index 474f4dc6e..7168c84a8 100644 --- a/lib/Exception/NoSuchFrameException.php +++ b/lib/Exception/NoSuchFrameException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoSuchFrameException extends WebDriverException { - -} \ No newline at end of file +class NoSuchFrameException extends WebDriverException +{ +} diff --git a/lib/Exception/NoSuchWindowException.php b/lib/Exception/NoSuchWindowException.php index bbeee4f0d..142d32e64 100644 --- a/lib/Exception/NoSuchWindowException.php +++ b/lib/Exception/NoSuchWindowException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class NoSuchWindowException extends WebDriverException { - -} \ No newline at end of file +class NoSuchWindowException extends WebDriverException +{ +} diff --git a/lib/Exception/NullPointerException.php b/lib/Exception/NullPointerException.php index 00f2fb5bb..cbc373a87 100644 --- a/lib/Exception/NullPointerException.php +++ b/lib/Exception/NullPointerException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class NullPointerException extends WebDriverException { - -} \ No newline at end of file +class NullPointerException extends WebDriverException +{ +} diff --git a/lib/Exception/ScriptTimeoutException.php b/lib/Exception/ScriptTimeoutException.php index 4095728a2..ed4203656 100644 --- a/lib/Exception/ScriptTimeoutException.php +++ b/lib/Exception/ScriptTimeoutException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class ScriptTimeoutException extends WebDriverException { - -} \ No newline at end of file +class ScriptTimeoutException extends WebDriverException +{ +} diff --git a/lib/Exception/SessionNotCreatedException.php b/lib/Exception/SessionNotCreatedException.php index 9b67edf94..f374141f1 100644 --- a/lib/Exception/SessionNotCreatedException.php +++ b/lib/Exception/SessionNotCreatedException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class SessionNotCreatedException extends WebDriverException { - -} \ No newline at end of file +class SessionNotCreatedException extends WebDriverException +{ +} diff --git a/lib/Exception/StaleElementReferenceException.php b/lib/Exception/StaleElementReferenceException.php index 7e265725c..2fbf99973 100644 --- a/lib/Exception/StaleElementReferenceException.php +++ b/lib/Exception/StaleElementReferenceException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class StaleElementReferenceException extends WebDriverException { - -} \ No newline at end of file +class StaleElementReferenceException extends WebDriverException +{ +} diff --git a/lib/Exception/TimeOutException.php b/lib/Exception/TimeOutException.php index 6301f4144..f7443e3d5 100644 --- a/lib/Exception/TimeOutException.php +++ b/lib/Exception/TimeOutException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class TimeOutException extends WebDriverException { - -} \ No newline at end of file +class TimeOutException extends WebDriverException +{ +} diff --git a/lib/Exception/UnableToSetCookieException.php b/lib/Exception/UnableToSetCookieException.php index 7ece63e50..0a1edae94 100644 --- a/lib/Exception/UnableToSetCookieException.php +++ b/lib/Exception/UnableToSetCookieException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class UnableToSetCookieException extends WebDriverException { - -} \ No newline at end of file +class UnableToSetCookieException extends WebDriverException +{ +} diff --git a/lib/Exception/UnexpectedAlertOpenException.php b/lib/Exception/UnexpectedAlertOpenException.php index e97eddeae..422255a77 100644 --- a/lib/Exception/UnexpectedAlertOpenException.php +++ b/lib/Exception/UnexpectedAlertOpenException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class UnexpectedAlertOpenException extends WebDriverException { - -} \ No newline at end of file +class UnexpectedAlertOpenException extends WebDriverException +{ +} diff --git a/lib/Exception/UnexpectedJavascriptException.php b/lib/Exception/UnexpectedJavascriptException.php index c8da7e505..5cf8a8f92 100644 --- a/lib/Exception/UnexpectedJavascriptException.php +++ b/lib/Exception/UnexpectedJavascriptException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class UnexpectedJavascriptException extends WebDriverException { - -} \ No newline at end of file +class UnexpectedJavascriptException extends WebDriverException +{ +} diff --git a/lib/Exception/UnexpectedTagNameException.php b/lib/Exception/UnexpectedTagNameException.php index 514abd374..0703c7d4e 100644 --- a/lib/Exception/UnexpectedTagNameException.php +++ b/lib/Exception/UnexpectedTagNameException.php @@ -15,20 +15,22 @@ namespace Facebook\WebDriver\Exception; -class UnexpectedTagNameException extends WebDriverException { - - /** - * @param string $expected_tag_name - * @param string $actual_tag_name - */ - public function __construct( - $expected_tag_name, - $actual_tag_name) { - parent::__construct( - sprintf( - "Element should have been \"%s\" but was \"%s\"", - $expected_tag_name, $actual_tag_name - ) - ); - } -} \ No newline at end of file +class UnexpectedTagNameException extends WebDriverException +{ + /** + * @param string $expected_tag_name + * @param string $actual_tag_name + */ + public function __construct( + $expected_tag_name, + $actual_tag_name + ) { + parent::__construct( + sprintf( + 'Element should have been "%s" but was "%s"', + $expected_tag_name, + $actual_tag_name + ) + ); + } +} diff --git a/lib/Exception/UnknownCommandException.php b/lib/Exception/UnknownCommandException.php index 2d20b0096..723d6dbef 100644 --- a/lib/Exception/UnknownCommandException.php +++ b/lib/Exception/UnknownCommandException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class UnknownCommandException extends WebDriverException { - -} \ No newline at end of file +class UnknownCommandException extends WebDriverException +{ +} diff --git a/lib/Exception/UnknownServerException.php b/lib/Exception/UnknownServerException.php index 13c3780c4..c24b415ef 100644 --- a/lib/Exception/UnknownServerException.php +++ b/lib/Exception/UnknownServerException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class UnknownServerException extends WebDriverException { - -} \ No newline at end of file +class UnknownServerException extends WebDriverException +{ +} diff --git a/lib/Exception/UnrecognizedExceptionException.php b/lib/Exception/UnrecognizedExceptionException.php index 9d0046dc0..fa1038605 100644 --- a/lib/Exception/UnrecognizedExceptionException.php +++ b/lib/Exception/UnrecognizedExceptionException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class UnrecognizedExceptionException extends WebDriverException { - -} \ No newline at end of file +class UnrecognizedExceptionException extends WebDriverException +{ +} diff --git a/lib/Exception/UnsupportedOperationException.php b/lib/Exception/UnsupportedOperationException.php index 781c2276a..64f8d1930 100644 --- a/lib/Exception/UnsupportedOperationException.php +++ b/lib/Exception/UnsupportedOperationException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class UnsupportedOperationException extends WebDriverException { - -} \ No newline at end of file +class UnsupportedOperationException extends WebDriverException +{ +} diff --git a/lib/Exception/WebDriverCurlException.php b/lib/Exception/WebDriverCurlException.php index 9719565d2..f559826c0 100644 --- a/lib/Exception/WebDriverCurlException.php +++ b/lib/Exception/WebDriverCurlException.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Exception; - -class WebDriverCurlException extends WebDriverException { - -} \ No newline at end of file +class WebDriverCurlException extends WebDriverException +{ +} diff --git a/lib/Exception/WebDriverException.php b/lib/Exception/WebDriverException.php index a23f42103..d05519b51 100644 --- a/lib/Exception/WebDriverException.php +++ b/lib/Exception/WebDriverException.php @@ -17,149 +17,152 @@ use Exception; -class WebDriverException extends Exception { +class WebDriverException extends Exception +{ + private $results; - private $results; - - /** - * @param string $message - * @param mixed $results - */ - public function __construct($message, $results = null) { - parent::__construct($message); - $this->results = $results; - } + /** + * @param string $message + * @param mixed $results + */ + public function __construct($message, $results = null) + { + parent::__construct($message); + $this->results = $results; + } - /** - * @return mixed - */ - public function getResults() { - return $this->results; - } + /** + * @return mixed + */ + public function getResults() + { + return $this->results; + } - /** - * Throw WebDriverExceptions. - * For $status_code >= 0, they are errors defined in the json wired protocol. - * For $status_code < 0, they are errors defined in php-webdriver. - * - * @param int $status_code - * @param string $message - * @param mixed $results - * - * @throws ElementNotSelectableException - * @throws ElementNotVisibleException - * @throws ExpectedException - * @throws IMEEngineActivationFailedException - * @throws IMENotAvailableException - * @throws IndexOutOfBoundsException - * @throws InvalidCookieDomainException - * @throws InvalidCoordinatesException - * @throws InvalidElementStateException - * @throws InvalidSelectorException - * @throws MoveTargetOutOfBoundsException - * @throws NoAlertOpenException - * @throws NoCollectionException - * @throws NoScriptResultException - * @throws NoStringException - * @throws NoStringLengthException - * @throws NoStringWrapperException - * @throws NoSuchCollectionException - * @throws NoSuchDocumentException - * @throws NoSuchDriverException - * @throws NoSuchElementException - * @throws NoSuchFrameException - * @throws NoSuchWindowException - * @throws NullPointerException - * @throws ScriptTimeoutException - * @throws SessionNotCreatedException - * @throws StaleElementReferenceException - * @throws TimeOutException - * @throws UnableToSetCookieException - * @throws UnexpectedAlertOpenException - * @throws UnexpectedJavascriptException - * @throws UnknownCommandException - * @throws UnknownServerException - * @throws UnrecognizedExceptionException - * @throws WebDriverCurlException - * @throws XPathLookupException - */ - public static function throwException($status_code, $message, $results) { - switch ($status_code) { - case -1: - throw new WebDriverCurlException($message); - case 0: - // Success - break; - case 1: - throw new IndexOutOfBoundsException($message, $results); - case 2: - throw new NoCollectionException($message, $results); - case 3: - throw new NoStringException($message, $results); - case 4: - throw new NoStringLengthException($message, $results); - case 5: - throw new NoStringWrapperException($message, $results); - case 6: - throw new NoSuchDriverException($message, $results); - case 7: - throw new NoSuchElementException($message, $results); - case 8: - throw new NoSuchFrameException($message, $results); - case 9: - throw new UnknownCommandException($message, $results); - case 10: - throw new StaleElementReferenceException($message, $results); - case 11: - throw new ElementNotVisibleException($message, $results); - case 12: - throw new InvalidElementStateException($message, $results); - case 13: - throw new UnknownServerException($message, $results); - case 14: - throw new ExpectedException($message, $results); - case 15: - throw new ElementNotSelectableException($message, $results); - case 16: - throw new NoSuchDocumentException($message, $results); - case 17: - throw new UnexpectedJavascriptException($message, $results); - case 18: - throw new NoScriptResultException($message, $results); - case 19: - throw new XPathLookupException($message, $results); - case 20: - throw new NoSuchCollectionException($message, $results); - case 21: - throw new TimeOutException($message, $results); - case 22: - throw new NullPointerException($message, $results); - case 23: - throw new NoSuchWindowException($message, $results); - case 24: - throw new InvalidCookieDomainException($message, $results); - case 25: - throw new UnableToSetCookieException($message, $results); - case 26: - throw new UnexpectedAlertOpenException($message, $results); - case 27: - throw new NoAlertOpenException($message, $results); - case 28: - throw new ScriptTimeoutException($message, $results); - case 29: - throw new InvalidCoordinatesException($message, $results); - case 30: - throw new IMENotAvailableException($message, $results); - case 31: - throw new IMEEngineActivationFailedException($message, $results); - case 32: - throw new InvalidSelectorException($message, $results); - case 33: - throw new SessionNotCreatedException($message, $results); - case 34: - throw new MoveTargetOutOfBoundsException($message, $results); - default: - throw new UnrecognizedExceptionException($message, $results); + /** + * Throw WebDriverExceptions. + * For $status_code >= 0, they are errors defined in the json wired protocol. + * For $status_code < 0, they are errors defined in php-webdriver. + * + * @param int $status_code + * @param string $message + * @param mixed $results + * + * @throws ElementNotSelectableException + * @throws ElementNotVisibleException + * @throws ExpectedException + * @throws IMEEngineActivationFailedException + * @throws IMENotAvailableException + * @throws IndexOutOfBoundsException + * @throws InvalidCookieDomainException + * @throws InvalidCoordinatesException + * @throws InvalidElementStateException + * @throws InvalidSelectorException + * @throws MoveTargetOutOfBoundsException + * @throws NoAlertOpenException + * @throws NoCollectionException + * @throws NoScriptResultException + * @throws NoStringException + * @throws NoStringLengthException + * @throws NoStringWrapperException + * @throws NoSuchCollectionException + * @throws NoSuchDocumentException + * @throws NoSuchDriverException + * @throws NoSuchElementException + * @throws NoSuchFrameException + * @throws NoSuchWindowException + * @throws NullPointerException + * @throws ScriptTimeoutException + * @throws SessionNotCreatedException + * @throws StaleElementReferenceException + * @throws TimeOutException + * @throws UnableToSetCookieException + * @throws UnexpectedAlertOpenException + * @throws UnexpectedJavascriptException + * @throws UnknownCommandException + * @throws UnknownServerException + * @throws UnrecognizedExceptionException + * @throws WebDriverCurlException + * @throws XPathLookupException + */ + public static function throwException($status_code, $message, $results) + { + switch ($status_code) { + case -1: + throw new WebDriverCurlException($message); + case 0: + // Success + break; + case 1: + throw new IndexOutOfBoundsException($message, $results); + case 2: + throw new NoCollectionException($message, $results); + case 3: + throw new NoStringException($message, $results); + case 4: + throw new NoStringLengthException($message, $results); + case 5: + throw new NoStringWrapperException($message, $results); + case 6: + throw new NoSuchDriverException($message, $results); + case 7: + throw new NoSuchElementException($message, $results); + case 8: + throw new NoSuchFrameException($message, $results); + case 9: + throw new UnknownCommandException($message, $results); + case 10: + throw new StaleElementReferenceException($message, $results); + case 11: + throw new ElementNotVisibleException($message, $results); + case 12: + throw new InvalidElementStateException($message, $results); + case 13: + throw new UnknownServerException($message, $results); + case 14: + throw new ExpectedException($message, $results); + case 15: + throw new ElementNotSelectableException($message, $results); + case 16: + throw new NoSuchDocumentException($message, $results); + case 17: + throw new UnexpectedJavascriptException($message, $results); + case 18: + throw new NoScriptResultException($message, $results); + case 19: + throw new XPathLookupException($message, $results); + case 20: + throw new NoSuchCollectionException($message, $results); + case 21: + throw new TimeOutException($message, $results); + case 22: + throw new NullPointerException($message, $results); + case 23: + throw new NoSuchWindowException($message, $results); + case 24: + throw new InvalidCookieDomainException($message, $results); + case 25: + throw new UnableToSetCookieException($message, $results); + case 26: + throw new UnexpectedAlertOpenException($message, $results); + case 27: + throw new NoAlertOpenException($message, $results); + case 28: + throw new ScriptTimeoutException($message, $results); + case 29: + throw new InvalidCoordinatesException($message, $results); + case 30: + throw new IMENotAvailableException($message, $results); + case 31: + throw new IMEEngineActivationFailedException($message, $results); + case 32: + throw new InvalidSelectorException($message, $results); + case 33: + throw new SessionNotCreatedException($message, $results); + case 34: + throw new MoveTargetOutOfBoundsException($message, $results); + default: + throw new UnrecognizedExceptionException($message, $results); + } } - } } diff --git a/lib/Exception/XPathLookupException.php b/lib/Exception/XPathLookupException.php index de9e2e707..c7f589dcc 100644 --- a/lib/Exception/XPathLookupException.php +++ b/lib/Exception/XPathLookupException.php @@ -15,6 +15,6 @@ namespace Facebook\WebDriver\Exception; -class XPathLookupException extends WebDriverException { - -} \ No newline at end of file +class XPathLookupException extends WebDriverException +{ +} diff --git a/lib/Firefox/FirefoxDriver.php b/lib/Firefox/FirefoxDriver.php index 083af226b..9e0751238 100644 --- a/lib/Firefox/FirefoxDriver.php +++ b/lib/Firefox/FirefoxDriver.php @@ -15,10 +15,11 @@ namespace Facebook\WebDriver\Firefox; -class FirefoxDriver { - const PROFILE = 'firefox_profile'; +class FirefoxDriver +{ + const PROFILE = 'firefox_profile'; - private function __construct() - { - } + private function __construct() + { + } } diff --git a/lib/Firefox/FirefoxPreferences.php b/lib/Firefox/FirefoxPreferences.php index 6b7ca91dd..b869a2667 100644 --- a/lib/Firefox/FirefoxPreferences.php +++ b/lib/Firefox/FirefoxPreferences.php @@ -19,15 +19,16 @@ * Constants of common Firefox profile preferences (about:config values). * @see http://kb.mozillazine.org/Firefox_:_FAQs_:_About:config_Entries */ -class FirefoxPreferences { - /** @var string Port WebDriver uses to communicate with Firefox instance */ - const WEBDRIVER_FIREFOX_PORT = 'webdriver_firefox_port'; - /** @var string Should the reader view (FF 38+) be enabled? */ - const READER_PARSE_ON_LOAD_ENABLED = 'reader.parse-on-load.enabled'; - /** @var string Browser homepage */ - const BROWSER_STARTUP_HOMEPAGE = 'browser.startup.homepage'; +class FirefoxPreferences +{ + /** @var string Port WebDriver uses to communicate with Firefox instance */ + const WEBDRIVER_FIREFOX_PORT = 'webdriver_firefox_port'; + /** @var string Should the reader view (FF 38+) be enabled? */ + const READER_PARSE_ON_LOAD_ENABLED = 'reader.parse-on-load.enabled'; + /** @var string Browser homepage */ + const BROWSER_STARTUP_HOMEPAGE = 'browser.startup.homepage'; - private function __construct() - { - } + private function __construct() + { + } } diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 03830dc63..925ac157f 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -21,256 +21,279 @@ use RecursiveIteratorIterator; use ZipArchive; -class FirefoxProfile { - - /** - * @var array - */ - private $preferences = array(); - - /** - * @var array - */ - private $extensions = array(); - - /** - * @var array - */ - private $extensions_datas = array(); - - /** - * @var string - */ - private $rdf_file; - - /** - * @param string $extension The path to the xpi extension. - * @return FirefoxProfile - */ - public function addExtension($extension) { - $this->extensions[] = $extension; - return $this; - } - - /** - * @param string $extension_datas The path to the folder containing the datas to add to the extension - * @return FirefoxProfile - */ - public function addExtensionDatas($extension_datas) { - if (!is_dir($extension_datas)) { - return; +class FirefoxProfile +{ + /** + * @var array + */ + private $preferences = array(); + /** + * @var array + */ + private $extensions = array(); + /** + * @var array + */ + private $extensions_datas = array(); + /** + * @var string + */ + private $rdf_file; + + /** + * @param string $extension The path to the xpi extension. + * @return FirefoxProfile + */ + public function addExtension($extension) + { + $this->extensions[] = $extension; + + return $this; } - $this->extensions_datas[basename($extension_datas)] = $extension_datas; - return $this; - } - - /** - * @param string $rdf_file The path to the rdf file - * @return FirefoxProfile - */ - public function setRdfFile($rdf_file) { - if (!is_file($rdf_file)) { - return; - } + /** + * @param string $extension_datas The path to the folder containing the datas to add to the extension + * @return FirefoxProfile + */ + public function addExtensionDatas($extension_datas) + { + if (!is_dir($extension_datas)) { + return null; + } - $this->rdf_file = $rdf_file; - return $this; - } - - /** - * @param string $key - * @param string|bool|int $value - * @return FirefoxProfile - * @throws WebDriverException - */ - public function setPreference($key, $value) { - if (is_string($value)) { - $value = sprintf('"%s"', $value); - } else if (is_int($value)) { - $value = sprintf('%d', $value); - } else if (is_bool($value)) { - $value = $value ? 'true' : 'false'; - } else { - throw new WebDriverException( - 'The value of the preference should be either a string, int or bool.'); - } - $this->preferences[$key] = $value; - return $this; - } - - /** - * @param $key - * @return mixed - */ - public function getPreference($key) - { - if (array_key_exists($key, $this->preferences)) { - return $this->preferences[$key]; - } + $this->extensions_datas[basename($extension_datas)] = $extension_datas; - return null; - } + return $this; + } - /** - * @return string - */ - public function encode() { - $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile'); + /** + * @param string $rdf_file The path to the rdf file + * @return FirefoxProfile + */ + public function setRdfFile($rdf_file) + { + if (!is_file($rdf_file)) { + return null; + } - if (isset($this->rdf_file)) { - copy($this->rdf_file, $temp_dir . DIRECTORY_SEPARATOR . "mimeTypes.rdf"); - } + $this->rdf_file = $rdf_file; - foreach ($this->extensions as $extension) { - $this->installExtension($extension, $temp_dir); + return $this; } - foreach ($this->extensions_datas as $dirname => $extension_datas) { - mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname); - $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($extension_datas, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST); - foreach ($iterator as $item) { - if ($item->isDir()) { - mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); + /** + * @param string $key + * @param string|bool|int $value + * @throws WebDriverException + * @return FirefoxProfile + */ + public function setPreference($key, $value) + { + if (is_string($value)) { + $value = sprintf('"%s"', $value); } else { - copy($item, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName()); + if (is_int($value)) { + $value = sprintf('%d', $value); + } else { + if (is_bool($value)) { + $value = $value ? 'true' : 'false'; + } else { + throw new WebDriverException( + 'The value of the preference should be either a string, int or bool.' + ); + } + } } - } + $this->preferences[$key] = $value; + + return $this; } - $content = ""; - foreach ($this->preferences as $key => $value) { - $content .= sprintf("user_pref(\"%s\", %s);\n", $key, $value); + /** + * @param $key + * @return mixed + */ + public function getPreference($key) + { + if (array_key_exists($key, $this->preferences)) { + return $this->preferences[$key]; + } + + return null; } - file_put_contents($temp_dir.'/user.js', $content); - $zip = new ZipArchive(); - $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverFirefoxProfileZip'); - $zip->open($temp_zip, ZipArchive::CREATE); + /** + * @return string + */ + public function encode() + { + $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfile'); + + if (isset($this->rdf_file)) { + copy($this->rdf_file, $temp_dir . DIRECTORY_SEPARATOR . 'mimeTypes.rdf'); + } + + foreach ($this->extensions as $extension) { + $this->installExtension($extension, $temp_dir); + } + + foreach ($this->extensions_datas as $dirname => $extension_datas) { + mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname); + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($extension_datas, RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST + ); + foreach ($iterator as $item) { + $target_dir = $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR + . $iterator->getSubPathName(); + + if ($item->isDir()) { + mkdir($target_dir); + } else { + copy($item, $target_dir); + } + } + } + + $content = ''; + foreach ($this->preferences as $key => $value) { + $content .= sprintf("user_pref(\"%s\", %s);\n", $key, $value); + } + file_put_contents($temp_dir . '/user.js', $content); + + $zip = new ZipArchive(); + $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverFirefoxProfileZip'); + $zip->open($temp_zip, ZipArchive::CREATE); + + $dir = new RecursiveDirectoryIterator($temp_dir); + $files = new RecursiveIteratorIterator($dir); - $dir = new RecursiveDirectoryIterator($temp_dir); - $files = new RecursiveIteratorIterator($dir); + $dir_prefix = preg_replace( + '#\\\\#', + '\\\\\\\\', + $temp_dir . DIRECTORY_SEPARATOR + ); - $dir_prefix = preg_replace( - '#\\\\#', - '\\\\\\\\', - $temp_dir.DIRECTORY_SEPARATOR - ); + foreach ($files as $name => $object) { + if (is_dir($name)) { + continue; + } - foreach ($files as $name => $object) { - if (is_dir($name)) { - continue; - } + $path = preg_replace("#^{$dir_prefix}#", '', $name); + $zip->addFile($name, $path); + } + $zip->close(); + + $profile = base64_encode(file_get_contents($temp_zip)); + + // clean up + $this->deleteDirectory($temp_dir); + unlink($temp_zip); + + return $profile; + } + + /** + * @param string $extension The path to the extension. + * @param string $profile_dir The path to the profile directory. + * @return string The path to the directory of this extension. + */ + private function installExtension($extension, $profile_dir) + { + $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfileExtension'); + $this->extractTo($extension, $temp_dir); + + // This is a hacky way to parse the id since there is no offical RDF parser library. + // Find the correct namespace for the id element. + $install_rdf_path = $temp_dir . '/install.rdf'; + $xml = simplexml_load_file($install_rdf_path); + $ns = $xml->getDocNamespaces(); + $prefix = ''; + if (!empty($ns)) { + foreach ($ns as $key => $value) { + if (strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) { + if ($key != '') { + $prefix = $key . ':'; // Separate the namespace from the name. + } + break; + } + } + } + // Get the extension id from the install manifest. + $matches = array(); + preg_match('#<' . $prefix . 'id>([^<]+)#', $xml->asXML(), $matches); + if (isset($matches[1])) { + $ext_dir = $profile_dir . '/extensions/' . $matches[1]; + mkdir($ext_dir, 0777, true); + $this->extractTo($extension, $ext_dir); + } + + // clean up + $this->deleteDirectory($temp_dir); - $path = preg_replace("#^{$dir_prefix}#", "", $name); - $zip->addFile($name, $path); + return $ext_dir; } - $zip->close(); - - $profile = base64_encode(file_get_contents($temp_zip)); - - // clean up - $this->deleteDirectory($temp_dir); - unlink($temp_zip); - - return $profile; - } - - /** - * @param string $extension The path to the extension. - * @param string $profile_dir The path to the profile directory. - * @return string The path to the directory of this extension. - */ - private function installExtension($extension, $profile_dir) { - $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfileExtension'); - $this->extractTo($extension, $temp_dir); - - // This is a hacky way to parse the id since there is no offical RDF parser library. - // Find the correct namespace for the id element. - $install_rdf_path = $temp_dir.'/install.rdf'; - $xml = simplexml_load_file($install_rdf_path); - $ns = $xml->getDocNamespaces(); - $prefix = ''; - if (!empty($ns)) { - foreach($ns as $key => $value) { - if (strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) { - if ($key != '') { - $prefix = $key . ':'; // Separate the namespace from the name. - } - break; - } - } - } - // Get the extension id from the install manifest. - $matches = array(); - preg_match('#<'.$prefix.'id>([^<]+)#', $xml->asXML(), $matches); - if (isset($matches[1])) { - $ext_dir = $profile_dir.'/extensions/'.$matches[1]; - mkdir($ext_dir, 0777, true); - $this->extractTo($extension, $ext_dir); - } - - // clean up - $this->deleteDirectory($temp_dir); - - return $ext_dir; - } - - /** - * @param string $prefix Prefix of the temp directory. - * - * @return string The path to the temp directory created. - * @throws WebDriverException - */ - private function createTempDirectory($prefix = '') { - $temp_dir = tempnam(sys_get_temp_dir(), $prefix); - if (file_exists($temp_dir)) { - unlink($temp_dir); - mkdir($temp_dir); - if (!is_dir($temp_dir)) { - throw new WebDriverException('Cannot create firefox profile.'); - } + + /** + * @param string $prefix Prefix of the temp directory. + * + * @throws WebDriverException + * @return string The path to the temp directory created. + */ + private function createTempDirectory($prefix = '') + { + $temp_dir = tempnam(sys_get_temp_dir(), $prefix); + if (file_exists($temp_dir)) { + unlink($temp_dir); + mkdir($temp_dir); + if (!is_dir($temp_dir)) { + throw new WebDriverException('Cannot create firefox profile.'); + } + } + + return $temp_dir; } - return $temp_dir; - } - - /** - * @param string $directory The path to the directory. - */ - private function deleteDirectory($directory) { - $dir = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS); - $paths = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST); - - foreach ($paths as $path) { - if ($path->isDir() && !$path->isLink()) { - rmdir($path->getPathname()); - } else { - unlink($path->getPathname()); - } + + /** + * @param string $directory The path to the directory. + */ + private function deleteDirectory($directory) + { + $dir = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS); + $paths = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST); + + foreach ($paths as $path) { + if ($path->isDir() && !$path->isLink()) { + rmdir($path->getPathname()); + } else { + unlink($path->getPathname()); + } + } + + rmdir($directory); } - rmdir($directory); - } - - /** - * @param string $xpi The path to the .xpi extension. - * @param string $target_dir The path to the unzip directory. - * - * @return FirefoxProfile - * @throws \Exception - */ - private function extractTo($xpi, $target_dir) { - $zip = new ZipArchive(); - if (file_exists($xpi)) { - if ($zip->open($xpi)) { - $zip->extractTo($target_dir); - $zip->close(); - } else { - throw new \Exception("Failed to open the firefox extension. '$xpi'"); - } - } else { - throw new \Exception("Firefox extension doesn't exist. '$xpi'"); + /** + * @param string $xpi The path to the .xpi extension. + * @param string $target_dir The path to the unzip directory. + * + * @throws \Exception + * @return FirefoxProfile + */ + private function extractTo($xpi, $target_dir) + { + $zip = new ZipArchive(); + if (file_exists($xpi)) { + if ($zip->open($xpi)) { + $zip->extractTo($target_dir); + $zip->close(); + } else { + throw new \Exception("Failed to open the firefox extension. '$xpi'"); + } + } else { + throw new \Exception("Firefox extension doesn't exist. '$xpi'"); + } + + return $this; } - return $this; - } } diff --git a/lib/Interactions/Internal/WebDriverButtonReleaseAction.php b/lib/Interactions/Internal/WebDriverButtonReleaseAction.php index a63570ae6..5df3cb6db 100644 --- a/lib/Interactions/Internal/WebDriverButtonReleaseAction.php +++ b/lib/Interactions/Internal/WebDriverButtonReleaseAction.php @@ -20,11 +20,10 @@ /** * Move to the location and then release the mouse key. */ -class WebDriverButtonReleaseAction - extends WebDriverMouseAction - implements WebDriverAction { - - public function perform() { - $this->mouse->mouseUp($this->getActionLocation()); - } +class WebDriverButtonReleaseAction extends WebDriverMouseAction implements WebDriverAction +{ + public function perform() + { + $this->mouse->mouseUp($this->getActionLocation()); + } } diff --git a/lib/Interactions/Internal/WebDriverClickAction.php b/lib/Interactions/Internal/WebDriverClickAction.php index f110d34bd..cf5bb9e68 100644 --- a/lib/Interactions/Internal/WebDriverClickAction.php +++ b/lib/Interactions/Internal/WebDriverClickAction.php @@ -17,11 +17,10 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverClickAction - extends WebDriverMouseAction - implements WebDriverAction { - - public function perform() { - $this->mouse->click($this->getActionLocation()); - } +class WebDriverClickAction extends WebDriverMouseAction implements WebDriverAction +{ + public function perform() + { + $this->mouse->click($this->getActionLocation()); + } } diff --git a/lib/Interactions/Internal/WebDriverClickAndHoldAction.php b/lib/Interactions/Internal/WebDriverClickAndHoldAction.php index 264d1503f..8f1907d84 100644 --- a/lib/Interactions/Internal/WebDriverClickAndHoldAction.php +++ b/lib/Interactions/Internal/WebDriverClickAndHoldAction.php @@ -20,11 +20,10 @@ /** * Move the the location, click and hold. */ -class WebDriverClickAndHoldAction - extends WebDriverMouseAction - implements WebDriverAction { - - public function perform() { - $this->mouse->mouseDown($this->getActionLocation()); - } +class WebDriverClickAndHoldAction extends WebDriverMouseAction implements WebDriverAction +{ + public function perform() + { + $this->mouse->mouseDown($this->getActionLocation()); + } } diff --git a/lib/Interactions/Internal/WebDriverContextClickAction.php b/lib/Interactions/Internal/WebDriverContextClickAction.php index d431173e9..175c60e3e 100644 --- a/lib/Interactions/Internal/WebDriverContextClickAction.php +++ b/lib/Interactions/Internal/WebDriverContextClickAction.php @@ -20,11 +20,10 @@ /** * You can call it 'Right Click' if you like. */ -class WebDriverContextClickAction - extends WebDriverMouseAction - implements WebDriverAction { - - public function perform() { - $this->mouse->contextClick($this->getActionLocation()); - } +class WebDriverContextClickAction extends WebDriverMouseAction implements WebDriverAction +{ + public function perform() + { + $this->mouse->contextClick($this->getActionLocation()); + } } diff --git a/lib/Interactions/Internal/WebDriverCoordinates.php b/lib/Interactions/Internal/WebDriverCoordinates.php index 89aae19bb..ca7069cb5 100644 --- a/lib/Interactions/Internal/WebDriverCoordinates.php +++ b/lib/Interactions/Internal/WebDriverCoordinates.php @@ -22,54 +22,53 @@ /** * Interface representing basic mouse operations. */ -class WebDriverCoordinates { +class WebDriverCoordinates +{ + private $onScreen; + private $inViewPort; + private $onPage; + private $auxiliary; - private - $onScreen, - $inViewPort, - $onPage, - $auxiliary; + public function __construct($on_screen, Closure $in_view_port, Closure $on_page, $auxiliary) + { + $this->onScreen = $on_screen; + $this->inViewPort = $in_view_port; + $this->onPage = $on_page; + $this->auxiliary = $auxiliary; + } - public function __construct( - $on_screen, - Closure $in_view_port, - Closure $on_page, - $auxiliary) { + /** + * @throws UnsupportedOperationException + * @return WebDriverPoint + */ + public function onScreen() + { + throw new UnsupportedOperationException( + 'onScreen is planned but not yet supported by Selenium' + ); + } - $this->onScreen = $on_screen; - $this->inViewPort = $in_view_port; - $this->onPage = $on_page; - $this->auxiliary = $auxiliary; - } + /** + * @return WebDriverPoint + */ + public function inViewPort() + { + return call_user_func($this->inViewPort); + } - /** - * @return WebDriverPoint - * @throws UnsupportedOperationException - */ - public function onScreen() { - throw new UnsupportedOperationException( - 'onScreen is planned but not yet supported by Selenium' - ); - } + /** + * @return WebDriverPoint + */ + public function onPage() + { + return call_user_func($this->onPage); + } - /** - * @return WebDriverPoint - */ - public function inViewPort() { - return call_user_func($this->inViewPort); - } - - /** - * @return WebDriverPoint - */ - public function onPage() { - return call_user_func($this->onPage); - } - - /** - * @return Object The attached object. - */ - public function getAuxiliary() { - return $this->auxiliary; - } + /** + * @return object The attached object. + */ + public function getAuxiliary() + { + return $this->auxiliary; + } } diff --git a/lib/Interactions/Internal/WebDriverDoubleClickAction.php b/lib/Interactions/Internal/WebDriverDoubleClickAction.php index 218a05b5e..46c197bbb 100644 --- a/lib/Interactions/Internal/WebDriverDoubleClickAction.php +++ b/lib/Interactions/Internal/WebDriverDoubleClickAction.php @@ -17,11 +17,10 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverDoubleClickAction - extends WebDriverMouseAction - implements WebDriverAction { - - public function perform() { - $this->mouse->doubleClick($this->getActionLocation()); - } +class WebDriverDoubleClickAction extends WebDriverMouseAction implements WebDriverAction +{ + public function perform() + { + $this->mouse->doubleClick($this->getActionLocation()); + } } diff --git a/lib/Interactions/Internal/WebDriverKeyDownAction.php b/lib/Interactions/Internal/WebDriverKeyDownAction.php index 29350e484..bb3820ed3 100644 --- a/lib/Interactions/Internal/WebDriverKeyDownAction.php +++ b/lib/Interactions/Internal/WebDriverKeyDownAction.php @@ -17,12 +17,11 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverKeyDownAction - extends WebDriverSingleKeyAction - implements WebDriverAction { - - public function perform() { - $this->focusOnElement(); - $this->keyboard->pressKey($this->key); - } +class WebDriverKeyDownAction extends WebDriverSingleKeyAction implements WebDriverAction +{ + public function perform() + { + $this->focusOnElement(); + $this->keyboard->pressKey($this->key); + } } diff --git a/lib/Interactions/Internal/WebDriverKeyUpAction.php b/lib/Interactions/Internal/WebDriverKeyUpAction.php index 9b89747eb..b675025e6 100644 --- a/lib/Interactions/Internal/WebDriverKeyUpAction.php +++ b/lib/Interactions/Internal/WebDriverKeyUpAction.php @@ -17,12 +17,11 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverKeyUpAction - extends WebDriverSingleKeyAction - implements WebDriverAction { - - public function perform() { - $this->focusOnElement(); - $this->keyboard->releaseKey($this->key); - } +class WebDriverKeyUpAction extends WebDriverSingleKeyAction implements WebDriverAction +{ + public function perform() + { + $this->focusOnElement(); + $this->keyboard->releaseKey($this->key); + } } diff --git a/lib/Interactions/Internal/WebDriverKeysRelatedAction.php b/lib/Interactions/Internal/WebDriverKeysRelatedAction.php index 77892cc25..b2f062750 100644 --- a/lib/Interactions/Internal/WebDriverKeysRelatedAction.php +++ b/lib/Interactions/Internal/WebDriverKeysRelatedAction.php @@ -16,38 +16,37 @@ namespace Facebook\WebDriver\Interactions\Internal; use Facebook\WebDriver\Internal\WebDriverLocatable; -use Facebook\WebDriver\WebDriverMouse; use Facebook\WebDriver\WebDriverKeyboard; +use Facebook\WebDriver\WebDriverMouse; /** * Base class for all keyboard-related actions. */ -abstract class WebDriverKeysRelatedAction { +abstract class WebDriverKeysRelatedAction +{ + protected $keyboard; + protected $mouse; + protected $locationProvider; - protected $keyboard; - protected $mouse; - protected $locationProvider; - - /** - * @param WebDriverKeyboard $keyboard - * @param WebDriverMouse $mouse - * @param WebDriverLocatable $location_provider - */ - public function __construct( - WebDriverKeyboard $keyboard, - WebDriverMouse $mouse, - WebDriverLocatable $location_provider = null) { - $this->keyboard = $keyboard; - $this->mouse = $mouse; - $this->locationProvider = $location_provider; - } + /** + * @param WebDriverKeyboard $keyboard + * @param WebDriverMouse $mouse + * @param WebDriverLocatable $location_provider + */ + public function __construct( + WebDriverKeyboard $keyboard, + WebDriverMouse $mouse, + WebDriverLocatable $location_provider = null + ) { + $this->keyboard = $keyboard; + $this->mouse = $mouse; + $this->locationProvider = $location_provider; + } - /** - * @return void - */ - protected function focusOnElement() { - if ($this->locationProvider) { - $this->mouse->click($this->locationProvider->getCoordinates()); + protected function focusOnElement() + { + if ($this->locationProvider) { + $this->mouse->click($this->locationProvider->getCoordinates()); + } } - } } diff --git a/lib/Interactions/Internal/WebDriverMouseAction.php b/lib/Interactions/Internal/WebDriverMouseAction.php index f6a115f43..8a13d86a7 100644 --- a/lib/Interactions/Internal/WebDriverMouseAction.php +++ b/lib/Interactions/Internal/WebDriverMouseAction.php @@ -15,46 +15,43 @@ namespace Facebook\WebDriver\Interactions\Internal; -use Facebook\WebDriver\WebDriverMouse; use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverMouse; /** * Base class for all mouse-related actions. */ -class WebDriverMouseAction { - - /** - * @var WebDriverMouse - */ - protected $mouse; - - /** - * @var WebDriverLocatable - */ - protected $locationProvider; +class WebDriverMouseAction +{ + /** + * @var WebDriverMouse + */ + protected $mouse; + /** + * @var WebDriverLocatable + */ + protected $locationProvider; + + public function __construct(WebDriverMouse $mouse, WebDriverLocatable $location_provider = null) + { + $this->mouse = $mouse; + $this->locationProvider = $location_provider; + } - public function __construct( - WebDriverMouse $mouse, - WebDriverLocatable $location_provider = null) { - $this->mouse = $mouse; - $this->locationProvider = $location_provider; - } + /** + * @return null|WebDriverCoordinates + */ + protected function getActionLocation() + { + if ($this->locationProvider !== null) { + return $this->locationProvider->getCoordinates(); + } - /** - * @return null|WebDriverCoordinates - */ - protected function getActionLocation() { - if ($this->locationProvider !== null) { - return $this->locationProvider->getCoordinates(); + return null; } - return null; - } - - /** - * @return void - */ - protected function moveToLocation() { - $this->mouse->mouseMove($this->locationProvider); - } + protected function moveToLocation() + { + $this->mouse->mouseMove($this->locationProvider); + } } diff --git a/lib/Interactions/Internal/WebDriverMouseMoveAction.php b/lib/Interactions/Internal/WebDriverMouseMoveAction.php index d229904fc..87c6d7cbb 100644 --- a/lib/Interactions/Internal/WebDriverMouseMoveAction.php +++ b/lib/Interactions/Internal/WebDriverMouseMoveAction.php @@ -17,11 +17,10 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverMouseMoveAction - extends WebDriverMouseAction - implements WebDriverAction { - - public function perform() { - $this->mouse->mouseMove($this->getActionLocation()); - } +class WebDriverMouseMoveAction extends WebDriverMouseAction implements WebDriverAction +{ + public function perform() + { + $this->mouse->mouseMove($this->getActionLocation()); + } } diff --git a/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php b/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php index f1e0270f8..7fffa0189 100644 --- a/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php +++ b/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php @@ -15,30 +15,32 @@ namespace Facebook\WebDriver\Interactions\Internal; -use Facebook\WebDriver\WebDriverAction; use Facebook\WebDriver\Internal\WebDriverLocatable; +use Facebook\WebDriver\WebDriverAction; use Facebook\WebDriver\WebDriverMouse; -class WebDriverMoveToOffsetAction - extends WebDriverMouseAction - implements WebDriverAction { - - private $xOffset, $yOffset; +class WebDriverMoveToOffsetAction extends WebDriverMouseAction implements WebDriverAction +{ + private $xOffset; + private $yOffset; - public function __construct(WebDriverMouse $mouse, - WebDriverLocatable $location_provider = null, - $x_offset = null, - $y_offset = null) { - parent::__construct($mouse, $location_provider); - $this->xOffset = $x_offset; - $this->yOffset = $y_offset; - } + public function __construct( + WebDriverMouse $mouse, + WebDriverLocatable $location_provider = null, + $x_offset = null, + $y_offset = null + ) { + parent::__construct($mouse, $location_provider); + $this->xOffset = $x_offset; + $this->yOffset = $y_offset; + } - public function perform() { - $this->mouse->mouseMove( - $this->getActionLocation(), - $this->xOffset, - $this->yOffset - ); - } + public function perform() + { + $this->mouse->mouseMove( + $this->getActionLocation(), + $this->xOffset, + $this->yOffset + ); + } } diff --git a/lib/Interactions/Internal/WebDriverSendKeysAction.php b/lib/Interactions/Internal/WebDriverSendKeysAction.php index 2c9512dd3..14836be38 100644 --- a/lib/Interactions/Internal/WebDriverSendKeysAction.php +++ b/lib/Interactions/Internal/WebDriverSendKeysAction.php @@ -15,34 +15,34 @@ namespace Facebook\WebDriver\Interactions\Internal; +use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverAction; use Facebook\WebDriver\WebDriverKeyboard; -use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverSendKeysAction - extends WebDriverKeysRelatedAction - implements WebDriverAction { - - private $keys; +class WebDriverSendKeysAction extends WebDriverKeysRelatedAction implements WebDriverAction +{ + private $keys; - /** - * @param WebDriverKeyboard $keyboard - * @param WebDriverMouse $mouse - * @param WebDriverLocatable $location_provider - * @param string $keys - */ - public function __construct( - WebDriverKeyboard $keyboard, - WebDriverMouse $mouse, - WebDriverLocatable $location_provider = null, - $keys = null) { - parent::__construct($keyboard, $mouse, $location_provider); - $this->keys = $keys; - } + /** + * @param WebDriverKeyboard $keyboard + * @param WebDriverMouse $mouse + * @param WebDriverLocatable $location_provider + * @param string $keys + */ + public function __construct( + WebDriverKeyboard $keyboard, + WebDriverMouse $mouse, + WebDriverLocatable $location_provider = null, + $keys = null + ) { + parent::__construct($keyboard, $mouse, $location_provider); + $this->keys = $keys; + } - public function perform() { - $this->focusOnElement(); - $this->keyboard->sendKeys($this->keys); - } + public function perform() + { + $this->focusOnElement(); + $this->keyboard->sendKeys($this->keys); + } } diff --git a/lib/Interactions/Internal/WebDriverSingleKeyAction.php b/lib/Interactions/Internal/WebDriverSingleKeyAction.php index 86cd74936..174304d15 100644 --- a/lib/Interactions/Internal/WebDriverSingleKeyAction.php +++ b/lib/Interactions/Internal/WebDriverSingleKeyAction.php @@ -15,23 +15,22 @@ namespace Facebook\WebDriver\Interactions\Internal; +use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverAction; use Facebook\WebDriver\WebDriverKeyboard; -use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -abstract class WebDriverSingleKeyAction - extends WebDriverKeysRelatedAction - implements WebDriverAction { - - protected $key; +abstract class WebDriverSingleKeyAction extends WebDriverKeysRelatedAction implements WebDriverAction +{ + protected $key; - public function __construct( - WebDriverKeyboard $keyboard, - WebDriverMouse $mouse, - WebDriverLocatable $location_provider = null, - $key = null) { - parent::__construct($keyboard, $mouse, $location_provider); - $this->key = $key; - } + public function __construct( + WebDriverKeyboard $keyboard, + WebDriverMouse $mouse, + WebDriverLocatable $location_provider = null, + $key = null + ) { + parent::__construct($keyboard, $mouse, $location_provider); + $this->key = $key; + } } diff --git a/lib/Interactions/Touch/WebDriverDoubleTapAction.php b/lib/Interactions/Touch/WebDriverDoubleTapAction.php index 92ccfa222..47664fe23 100644 --- a/lib/Interactions/Touch/WebDriverDoubleTapAction.php +++ b/lib/Interactions/Touch/WebDriverDoubleTapAction.php @@ -17,11 +17,10 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverDoubleTapAction - extends WebDriverTouchAction - implements WebDriverAction { - - public function perform() { - $this->touchScreen->doubleTap($this->locationProvider); - } +class WebDriverDoubleTapAction extends WebDriverTouchAction implements WebDriverAction +{ + public function perform() + { + $this->touchScreen->doubleTap($this->locationProvider); + } } diff --git a/lib/Interactions/Touch/WebDriverDownAction.php b/lib/Interactions/Touch/WebDriverDownAction.php index eb946008f..46224aea2 100644 --- a/lib/Interactions/Touch/WebDriverDownAction.php +++ b/lib/Interactions/Touch/WebDriverDownAction.php @@ -17,25 +17,25 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverDownAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverDownAction extends WebDriverTouchAction implements WebDriverAction +{ + private $x; + private $y; - private $x; - private $y; + /** + * @param WebDriverTouchScreen $touch_screen + * @param int $x + * @param int $y + */ + public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) + { + $this->x = $x; + $this->y = $y; + parent::__construct($touch_screen); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param int $x - * @param int $y - */ - public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) { - $this->x = $x; - $this->y = $y; - parent::__construct($touch_screen); - } - - public function perform() { - $this->touchScreen->down($this->x, $this->y); - } + public function perform() + { + $this->touchScreen->down($this->x, $this->y); + } } diff --git a/lib/Interactions/Touch/WebDriverFlickAction.php b/lib/Interactions/Touch/WebDriverFlickAction.php index 575c3eb4d..48e65dc95 100644 --- a/lib/Interactions/Touch/WebDriverFlickAction.php +++ b/lib/Interactions/Touch/WebDriverFlickAction.php @@ -17,22 +17,22 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverFlickAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverFlickAction extends WebDriverTouchAction implements WebDriverAction +{ + /** + * @param WebDriverTouchScreen $touch_screen + * @param int $x + * @param int $y + */ + public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) + { + $this->x = $x; + $this->y = $y; + parent::__construct($touch_screen); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param int $x - * @param int $y - */ - public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) { - $this->x = $x; - $this->y = $y; - parent::__construct($touch_screen); - } - - public function perform() { - $this->touchScreen->flick($this->x, $this->y); - } + public function perform() + { + $this->touchScreen->flick($this->x, $this->y); + } } diff --git a/lib/Interactions/Touch/WebDriverFlickFromElementAction.php b/lib/Interactions/Touch/WebDriverFlickFromElementAction.php index afd13ab8c..d91e84898 100644 --- a/lib/Interactions/Touch/WebDriverFlickFromElementAction.php +++ b/lib/Interactions/Touch/WebDriverFlickFromElementAction.php @@ -18,37 +18,39 @@ use Facebook\WebDriver\WebDriverAction; use Facebook\WebDriver\WebDriverElement; -class WebDriverFlickFromElementAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverFlickFromElementAction extends WebDriverTouchAction implements WebDriverAction +{ + private $x; + private $y; + private $speed; - private $x; - private $y; - private $speed; + /** + * @param WebDriverTouchScreen $touch_screen + * @param WebDriverElement $element + * @param int $x + * @param int $y + * @param int $speed + */ + public function __construct( + WebDriverTouchScreen $touch_screen, + WebDriverElement $element, + $x, + $y, + $speed + ) { + $this->x = $x; + $this->y = $y; + $this->speed = $speed; + parent::__construct($touch_screen, $element); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param WebDriverElement $element - * @param int $x - * @param int $y - * @param int $speed - */ - public function __construct( - WebDriverTouchScreen $touch_screen, - WebDriverElement $element, $x, $y, $speed - ) { - $this->x = $x; - $this->y = $y; - $this->speed = $speed; - parent::__construct($touch_screen, $element); - } - - public function perform() { - $this->touchScreen->flickFromElement( - $this->locationProvider, - $this->x, - $this->y, - $this->speed - ); - } + public function perform() + { + $this->touchScreen->flickFromElement( + $this->locationProvider, + $this->x, + $this->y, + $this->speed + ); + } } diff --git a/lib/Interactions/Touch/WebDriverLongPressAction.php b/lib/Interactions/Touch/WebDriverLongPressAction.php index c46770d86..bf6e8bf49 100644 --- a/lib/Interactions/Touch/WebDriverLongPressAction.php +++ b/lib/Interactions/Touch/WebDriverLongPressAction.php @@ -17,11 +17,10 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverLongPressAction - extends WebDriverTouchAction - implements WebDriverAction { - - public function perform() { - $this->touchScreen->longPress($this->locationProvider); - } +class WebDriverLongPressAction extends WebDriverTouchAction implements WebDriverAction +{ + public function perform() + { + $this->touchScreen->longPress($this->locationProvider); + } } diff --git a/lib/Interactions/Touch/WebDriverMoveAction.php b/lib/Interactions/Touch/WebDriverMoveAction.php index 330783271..bb2a4bab1 100644 --- a/lib/Interactions/Touch/WebDriverMoveAction.php +++ b/lib/Interactions/Touch/WebDriverMoveAction.php @@ -17,25 +17,25 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverMoveAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverMoveAction extends WebDriverTouchAction implements WebDriverAction +{ + private $x; + private $y; - private $x; - private $y; + /** + * @param WebDriverTouchScreen $touch_screen + * @param int $x + * @param int $y + */ + public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) + { + $this->x = $x; + $this->y = $y; + parent::__construct($touch_screen); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param int $x - * @param int $y - */ - public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) { - $this->x = $x; - $this->y = $y; - parent::__construct($touch_screen); - } - - public function perform() { - $this->touchScreen->move($this->x, $this->y); - } + public function perform() + { + $this->touchScreen->move($this->x, $this->y); + } } diff --git a/lib/Interactions/Touch/WebDriverScrollAction.php b/lib/Interactions/Touch/WebDriverScrollAction.php index 8dc1f14b7..0bb70a8e5 100644 --- a/lib/Interactions/Touch/WebDriverScrollAction.php +++ b/lib/Interactions/Touch/WebDriverScrollAction.php @@ -17,25 +17,25 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverScrollAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverScrollAction extends WebDriverTouchAction implements WebDriverAction +{ + private $x; + private $y; - private $x; - private $y; + /** + * @param WebDriverTouchScreen $touch_screen + * @param int $x + * @param int $y + */ + public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) + { + $this->x = $x; + $this->y = $y; + parent::__construct($touch_screen); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param int $x - * @param int $y - */ - public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) { - $this->x = $x; - $this->y = $y; - parent::__construct($touch_screen); - } - - public function perform() { - $this->touchScreen->scroll($this->x, $this->y); - } + public function perform() + { + $this->touchScreen->scroll($this->x, $this->y); + } } diff --git a/lib/Interactions/Touch/WebDriverScrollFromElementAction.php b/lib/Interactions/Touch/WebDriverScrollFromElementAction.php index df31f13b0..073244480 100644 --- a/lib/Interactions/Touch/WebDriverScrollFromElementAction.php +++ b/lib/Interactions/Touch/WebDriverScrollFromElementAction.php @@ -18,32 +18,34 @@ use Facebook\WebDriver\WebDriverAction; use Facebook\WebDriver\WebDriverElement; -class WebDriverScrollFromElementAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverScrollFromElementAction extends WebDriverTouchAction implements WebDriverAction +{ + private $x; + private $y; - private $x; - private $y; + /** + * @param WebDriverTouchScreen $touch_screen + * @param WebDriverElement $element + * @param int $x + * @param int $y + */ + public function __construct( + WebDriverTouchScreen $touch_screen, + WebDriverElement $element, + $x, + $y + ) { + $this->x = $x; + $this->y = $y; + parent::__construct($touch_screen, $element); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param WebDriverElement $element - * @param int $x - * @param int $y - */ - public function __construct( - WebDriverTouchScreen $touch_screen, WebDriverElement $element, $x, $y - ) { - $this->x = $x; - $this->y = $y; - parent::__construct($touch_screen, $element); - } - - public function perform() { - $this->touchScreen->scrollFromElement( - $this->locationProvider, - $this->x, - $this->y - ); - } + public function perform() + { + $this->touchScreen->scrollFromElement( + $this->locationProvider, + $this->x, + $this->y + ); + } } diff --git a/lib/Interactions/Touch/WebDriverTapAction.php b/lib/Interactions/Touch/WebDriverTapAction.php index 835acc848..31ccf5678 100644 --- a/lib/Interactions/Touch/WebDriverTapAction.php +++ b/lib/Interactions/Touch/WebDriverTapAction.php @@ -17,11 +17,10 @@ use Facebook\WebDriver\WebDriverAction; -class WebDriverTapAction - extends WebDriverTouchAction - implements WebDriverAction { - - public function perform() { - $this->touchScreen->tap($this->locationProvider); - } +class WebDriverTapAction extends WebDriverTouchAction implements WebDriverAction +{ + public function perform() + { + $this->touchScreen->tap($this->locationProvider); + } } diff --git a/lib/Interactions/Touch/WebDriverTouchAction.php b/lib/Interactions/Touch/WebDriverTouchAction.php index e267f1ab3..dd09e6499 100644 --- a/lib/Interactions/Touch/WebDriverTouchAction.php +++ b/lib/Interactions/Touch/WebDriverTouchAction.php @@ -15,42 +15,41 @@ namespace Facebook\WebDriver\Interactions\Touch; -use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates; +use Facebook\WebDriver\Internal\WebDriverLocatable; /** * Base class for all touch-related actions. */ -abstract class WebDriverTouchAction { - - /** - * @var WebDriverTouchScreen - */ - protected $touchScreen; - - /** - * @var WebDriverLocatable - */ - protected $locationProvider; - - /** - * @param WebDriverTouchScreen $touch_screen - * @param WebDriverLocatable $location_provider - */ - public function __construct( - WebDriverTouchScreen $touch_screen, - WebDriverLocatable $location_provider = null - ) { - $this->touchScreen = $touch_screen; - $this->locationProvider = $location_provider; - } - - /** - * @return null|WebDriverCoordinates - */ - protected function getActionLocation() { - return $this->locationProvider !== null - ? $this->locationProvider->getCoordinates() : null; - } - +abstract class WebDriverTouchAction +{ + /** + * @var WebDriverTouchScreen + */ + protected $touchScreen; + /** + * @var WebDriverLocatable + */ + protected $locationProvider; + + /** + * @param WebDriverTouchScreen $touch_screen + * @param WebDriverLocatable $location_provider + */ + public function __construct( + WebDriverTouchScreen $touch_screen, + WebDriverLocatable $location_provider = null + ) { + $this->touchScreen = $touch_screen; + $this->locationProvider = $location_provider; + } + + /** + * @return null|WebDriverCoordinates + */ + protected function getActionLocation() + { + return $this->locationProvider !== null + ? $this->locationProvider->getCoordinates() : null; + } } diff --git a/lib/Interactions/Touch/WebDriverTouchScreen.php b/lib/Interactions/Touch/WebDriverTouchScreen.php index cb753cd0d..4bb6f1100 100644 --- a/lib/Interactions/Touch/WebDriverTouchScreen.php +++ b/lib/Interactions/Touch/WebDriverTouchScreen.php @@ -20,103 +20,108 @@ /** * Interface representing touch screen operations. */ -interface WebDriverTouchScreen { +interface WebDriverTouchScreen +{ + /** + * Single tap on the touch enabled device. + * + * @param WebDriverElement $element + * @return $this + */ + public function tap(WebDriverElement $element); - /** - * Single tap on the touch enabled device. - * - * @param WebDriverElement $element - * @return $this - */ - public function tap(WebDriverElement $element); + /** + * Double tap on the touch screen using finger motion events. + * + * @param WebDriverElement $element + * @return $this + */ + public function doubleTap(WebDriverElement $element); - /** - * Double tap on the touch screen using finger motion events. - * - * @param WebDriverElement $element - * @return $this - */ - public function doubleTap(WebDriverElement $element); + /** + * Finger down on the screen. + * + * @param int $x + * @param int $y + * @return $this + */ + public function down($x, $y); - /** - * Finger down on the screen. - * - * @param int $x - * @param int $y - * @return $this - */ - public function down($x, $y); + /** + * Flick on the touch screen using finger motion events. Use this flick + * command if you don't care where the flick starts on the screen. + * + * @param int $xspeed + * @param int $yspeed + * @return $this + */ + public function flick($xspeed, $yspeed); - /** - * Flick on the touch screen using finger motion events. Use this flick - * command if you don't care where the flick starts on the screen. - * - * @param int $xspeed - * @param int $yspeed - * @return $this - */ - public function flick($xspeed, $yspeed); + /** + * Flick on the touch screen using finger motion events. + * This flickcommand starts at a particular screen location. + * + * @param WebDriverElement $element + * @param int $xoffset + * @param int $yoffset + * @param int $speed + * @return $this + */ + public function flickFromElement( + WebDriverElement $element, + $xoffset, + $yoffset, + $speed + ); - /** - * Flick on the touch screen using finger motion events. - * This flickcommand starts at a particular screen location. - * - * @param WebDriverElement $element - * @param int $xoffset - * @param int $yoffset - * @param int $speed - * @return $this - */ - public function flickFromElement( - WebDriverElement $element, $xoffset, $yoffset, $speed); + /** + * Long press on the touch screen using finger motion events. + * + * @param WebDriverElement $element + * @return $this + */ + public function longPress(WebDriverElement $element); - /** - * Long press on the touch screen using finger motion events. - * - * @param WebDriverElement $element - * @return $this - */ - public function longPress(WebDriverElement $element); + /** + * Finger move on the screen. + * + * @param int $x + * @param int $y + * @return $this + */ + public function move($x, $y); - /** - * Finger move on the screen. - * - * @param int $x - * @param int $y - * @return $this - */ - public function move($x, $y); + /** + * Scroll on the touch screen using finger based motion events. Use this + * command if you don't care where the scroll starts on the screen. + * + * @param int $xoffset + * @param int $yoffset + * @return $this + */ + public function scroll($xoffset, $yoffset); + /** + * Scroll on the touch screen using finger based motion events. Use this + * command to start scrolling at a particular screen location. + * + * @param WebDriverElement $element + * @param int $xoffset + * @param int $yoffset + * @return $this + */ + public function scrollFromElement( + WebDriverElement $element, + $xoffset, + $yoffset + ); - /** - * Scroll on the touch screen using finger based motion events. Use this - * command if you don't care where the scroll starts on the screen. - * - * @param int $xoffset - * @param int $yoffset - * @return $this - */ - public function scroll($xoffset, $yoffset); - - /** - * Scroll on the touch screen using finger based motion events. Use this - * command to start scrolling at a particular screen location. - * - * @param WebDriverElement $element - * @param int $xoffset - * @param int $yoffset - * @return $this - */ - public function scrollFromElement( - WebDriverElement $element, $xoffset, $yoffset); - - /** - * Finger up on the screen. - * - * @param int $x - * @param int $y - * @return $this - */ - public function up($x, $y); - + /** + * Finger up on the screen. + * + * @param int $x + * @param int $y + * @return $this + */ + public function up($x, $y); } diff --git a/lib/Interactions/WebDriverActions.php b/lib/Interactions/WebDriverActions.php index 3e11b3c0a..860cf8d5a 100644 --- a/lib/Interactions/WebDriverActions.php +++ b/lib/Interactions/WebDriverActions.php @@ -15,237 +15,264 @@ namespace Facebook\WebDriver\Interactions; -use Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction; -use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction; use Facebook\WebDriver\Interactions\Internal\WebDriverButtonReleaseAction; -use Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction; -use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction; use Facebook\WebDriver\Interactions\Internal\WebDriverClickAction; -use Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction; +use Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction; use Facebook\WebDriver\Interactions\Internal\WebDriverContextClickAction; +use Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction; +use Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction; use Facebook\WebDriver\Interactions\Internal\WebDriverKeyUpAction; use Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction; -use Facebook\WebDriver\WebDriverElement; +use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction; +use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction; use Facebook\WebDriver\WebDriver; +use Facebook\WebDriver\WebDriverElement; /** * WebDriver action builder. It implements the builder pattern. */ -class WebDriverActions { - - protected $driver; - protected $keyboard; - protected $mouse; - protected $action; - - public function __construct(WebDriver $driver) { - $this->driver = $driver; - $this->keyboard = $driver->getKeyboard(); - $this->mouse = $driver->getMouse(); - $this->action = new WebDriverCompositeAction(); - } - - /** - * A convenience method for performing the actions without calling build(). - * @return void - */ - public function perform() { - $this->action->perform(); - } - - /** - * Mouse click. - * If $element is provided, move to the middle of the element first. - * - * @param WebDriverElement $element - * @return WebDriverActions - */ - public function click(WebDriverElement $element = null) { - $this->action->addAction( - new WebDriverClickAction($this->mouse, $element) - ); - return $this; - } - - /** - * Mouse click and hold. - * If $element is provided, move to the middle of the element first. - * - * @param WebDriverElement $element - * @return WebDriverActions - */ - public function clickAndHold(WebDriverElement $element = null) { - $this->action->addAction( - new WebDriverClickAndHoldAction($this->mouse, $element) - ); - return $this; - } - - /** - * Context-click (right click). - * If $element is provided, move to the middle of the element first. - * - * @param WebDriverElement $element - * @return WebDriverActions - */ - public function contextClick(WebDriverElement $element = null) { - $this->action->addAction( - new WebDriverContextClickAction($this->mouse, $element) - ); - return $this; - } - - /** - * Double click. - * If $element is provided, move to the middle of the element first. - * - * @param WebDriverElement $element - * @return WebDriverActions - */ - public function doubleClick(WebDriverElement $element = null) { - $this->action->addAction( - new WebDriverDoubleClickAction($this->mouse, $element) - ); - return $this; - } - - /** - * Drag and drop from $source to $target. - * - * @param WebDriverElement $source - * @param WebDriverElement $target - * @return WebDriverActions - */ - public function dragAndDrop(WebDriverElement $source, - WebDriverElement $target) { - $this->action->addAction( - new WebDriverClickAndHoldAction($this->mouse, $source) - ); - $this->action->addAction( - new WebDriverMouseMoveAction($this->mouse, $target) - ); - $this->action->addAction( - new WebDriverButtonReleaseAction($this->mouse, $target) - ); - return $this; - } - - /** - * Drag $source and drop by offset ($x_offset, $y_offset). - * - * @param WebDriverElement $source - * @param int $x_offset - * @param int $y_offset - * @return WebDriverActions - */ - public function dragAndDropBy(WebDriverElement $source, - $x_offset, - $y_offset) { - $this->action->addAction( - new WebDriverClickAndHoldAction($this->mouse, $source) - ); - $this->action->addAction( - new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset) - ); - $this->action->addAction( - new WebDriverButtonReleaseAction($this->mouse, null) - ); - return $this; - } - - /** - * Mouse move by offset. - * - * @param int $x_offset - * @param int $y_offset - * @return WebDriverActions - */ - public function moveByOffset($x_offset, $y_offset) { - $this->action->addAction( - new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset) - ); - return $this; - } - - /** - * Move to the middle of the given WebDriverElement. - * Extra shift, calculated from the top-left corner of the element, can be set by passing $x_offset and $y_offset parameters. - * - * @param WebDriverElement $element - * @param int $x_offset - * @param int $y_offset - * @return WebDriverActions - */ - public function moveToElement(WebDriverElement $element, - $x_offset = null, - $y_offset = null) { - $this->action->addAction(new WebDriverMoveToOffsetAction( - $this->mouse, $element, $x_offset, $y_offset - )); - return $this; - } - - /** - * Release the mouse button. - * If $element is provided, move to the middle of the element first. - * - * @param WebDriverElement $element - * @return WebDriverActions - */ - public function release(WebDriverElement $element = null) { - $this->action->addAction( - new WebDriverButtonReleaseAction($this->mouse, $element) - ); - return $this; - } - - /** - * Press a key on keyboard. - * If $element is provided, focus on that element first. - * - * @see WebDriverKeys for special keys like CONTROL, ALT, etc. - * @param WebDriverElement $element - * @param string $key - * @return WebDriverActions - */ - public function keyDown(WebDriverElement $element = null, $key = null) { - $this->action->addAction( - new WebDriverKeyDownAction($this->keyboard, $this->mouse, $element, $key) - ); - return $this; - } - - /** - * Release a key on keyboard. - * If $element is provided, focus on that element first. - * - * @see WebDriverKeys for special keys like CONTROL, ALT, etc. - * @param WebDriverElement $element - * @param string $key - * @return WebDriverActions - */ - public function keyUp(WebDriverElement $element = null, $key = null) { - $this->action->addAction( - new WebDriverKeyUpAction($this->keyboard, $this->mouse, $element, $key) - ); - return $this; - } - - /** - * Send keys by keyboard. - * If $element is provided, focus on that element first. - * - * @see WebDriverKeys for special keys like CONTROL, ALT, etc. - * @param WebDriverElement $element - * @param string $keys - * @return WebDriverActions - */ - public function sendKeys(WebDriverElement $element = null, $keys = null) { - $this->action->addAction( - new WebDriverSendKeysAction( - $this->keyboard, $this->mouse, $element, $keys - ) - ); - return $this; - } +class WebDriverActions +{ + protected $driver; + protected $keyboard; + protected $mouse; + protected $action; + + public function __construct(WebDriver $driver) + { + $this->driver = $driver; + $this->keyboard = $driver->getKeyboard(); + $this->mouse = $driver->getMouse(); + $this->action = new WebDriverCompositeAction(); + } + + /** + * A convenience method for performing the actions without calling build(). + */ + public function perform() + { + $this->action->perform(); + } + + /** + * Mouse click. + * If $element is provided, move to the middle of the element first. + * + * @param WebDriverElement $element + * @return WebDriverActions + */ + public function click(WebDriverElement $element = null) + { + $this->action->addAction( + new WebDriverClickAction($this->mouse, $element) + ); + + return $this; + } + + /** + * Mouse click and hold. + * If $element is provided, move to the middle of the element first. + * + * @param WebDriverElement $element + * @return WebDriverActions + */ + public function clickAndHold(WebDriverElement $element = null) + { + $this->action->addAction( + new WebDriverClickAndHoldAction($this->mouse, $element) + ); + + return $this; + } + + /** + * Context-click (right click). + * If $element is provided, move to the middle of the element first. + * + * @param WebDriverElement $element + * @return WebDriverActions + */ + public function contextClick(WebDriverElement $element = null) + { + $this->action->addAction( + new WebDriverContextClickAction($this->mouse, $element) + ); + + return $this; + } + + /** + * Double click. + * If $element is provided, move to the middle of the element first. + * + * @param WebDriverElement $element + * @return WebDriverActions + */ + public function doubleClick(WebDriverElement $element = null) + { + $this->action->addAction( + new WebDriverDoubleClickAction($this->mouse, $element) + ); + + return $this; + } + + /** + * Drag and drop from $source to $target. + * + * @param WebDriverElement $source + * @param WebDriverElement $target + * @return WebDriverActions + */ + public function dragAndDrop(WebDriverElement $source, WebDriverElement $target) + { + $this->action->addAction( + new WebDriverClickAndHoldAction($this->mouse, $source) + ); + $this->action->addAction( + new WebDriverMouseMoveAction($this->mouse, $target) + ); + $this->action->addAction( + new WebDriverButtonReleaseAction($this->mouse, $target) + ); + + return $this; + } + + /** + * Drag $source and drop by offset ($x_offset, $y_offset). + * + * @param WebDriverElement $source + * @param int $x_offset + * @param int $y_offset + * @return WebDriverActions + */ + public function dragAndDropBy(WebDriverElement $source, $x_offset, $y_offset) + { + $this->action->addAction( + new WebDriverClickAndHoldAction($this->mouse, $source) + ); + $this->action->addAction( + new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset) + ); + $this->action->addAction( + new WebDriverButtonReleaseAction($this->mouse, null) + ); + + return $this; + } + + /** + * Mouse move by offset. + * + * @param int $x_offset + * @param int $y_offset + * @return WebDriverActions + */ + public function moveByOffset($x_offset, $y_offset) + { + $this->action->addAction( + new WebDriverMoveToOffsetAction($this->mouse, null, $x_offset, $y_offset) + ); + + return $this; + } + + /** + * Move to the middle of the given WebDriverElement. + * Extra shift, calculated from the top-left corner of the element, can be set by passing $x_offset and $y_offset + * parameters. + * + * @param WebDriverElement $element + * @param int $x_offset + * @param int $y_offset + * @return WebDriverActions + */ + public function moveToElement(WebDriverElement $element, $x_offset = null, $y_offset = null) + { + $this->action->addAction(new WebDriverMoveToOffsetAction( + $this->mouse, + $element, + $x_offset, + $y_offset + )); + + return $this; + } + + /** + * Release the mouse button. + * If $element is provided, move to the middle of the element first. + * + * @param WebDriverElement $element + * @return WebDriverActions + */ + public function release(WebDriverElement $element = null) + { + $this->action->addAction( + new WebDriverButtonReleaseAction($this->mouse, $element) + ); + + return $this; + } + + /** + * Press a key on keyboard. + * If $element is provided, focus on that element first. + * + * @see WebDriverKeys for special keys like CONTROL, ALT, etc. + * @param WebDriverElement $element + * @param string $key + * @return WebDriverActions + */ + public function keyDown(WebDriverElement $element = null, $key = null) + { + $this->action->addAction( + new WebDriverKeyDownAction($this->keyboard, $this->mouse, $element, $key) + ); + + return $this; + } + + /** + * Release a key on keyboard. + * If $element is provided, focus on that element first. + * + * @see WebDriverKeys for special keys like CONTROL, ALT, etc. + * @param WebDriverElement $element + * @param string $key + * @return WebDriverActions + */ + public function keyUp(WebDriverElement $element = null, $key = null) + { + $this->action->addAction( + new WebDriverKeyUpAction($this->keyboard, $this->mouse, $element, $key) + ); + + return $this; + } + + /** + * Send keys by keyboard. + * If $element is provided, focus on that element first. + * + * @see WebDriverKeys for special keys like CONTROL, ALT, etc. + * @param WebDriverElement $element + * @param string $keys + * @return WebDriverActions + */ + public function sendKeys(WebDriverElement $element = null, $keys = null) + { + $this->action->addAction( + new WebDriverSendKeysAction( + $this->keyboard, + $this->mouse, + $element, + $keys + ) + ); + + return $this; + } } diff --git a/lib/Interactions/WebDriverCompositeAction.php b/lib/Interactions/WebDriverCompositeAction.php index 63d9863d7..f17cc4588 100644 --- a/lib/Interactions/WebDriverCompositeAction.php +++ b/lib/Interactions/WebDriverCompositeAction.php @@ -20,36 +20,40 @@ /** * An action for aggregating actions and triggering all of them afterwards. */ -class WebDriverCompositeAction implements WebDriverAction { +class WebDriverCompositeAction implements WebDriverAction +{ + private $actions = array(); - private $actions = array(); + /** + * Add an WebDriverAction to the sequence. + * + * @param WebDriverAction $action + * @return WebDriverCompositeAction The current instance. + */ + public function addAction(WebDriverAction $action) + { + $this->actions[] = $action; - /** - * Add an WebDriverAction to the sequence. - * - * @param WebDriverAction $action - * @return WebDriverCompositeAction The current instance. - */ - public function addAction(WebDriverAction $action) { - $this->actions[] = $action; - return $this; - } + return $this; + } - /** - * Get the number of actions in the sequence. - * - * @return int The number of actions. - */ - public function getNumberOfActions() { - return count($this->actions); - } + /** + * Get the number of actions in the sequence. + * + * @return int The number of actions. + */ + public function getNumberOfActions() + { + return count($this->actions); + } - /** - * Perform the seqeunce of actions. - */ - public function perform() { - foreach ($this->actions as $action) { - $action->perform(); + /** + * Perform the seqeunce of actions. + */ + public function perform() + { + foreach ($this->actions as $action) { + $action->perform(); + } } - } } diff --git a/lib/Interactions/WebDriverTouchActions.php b/lib/Interactions/WebDriverTouchActions.php index ec77242fc..d8cf05f4b 100644 --- a/lib/Interactions/WebDriverTouchActions.php +++ b/lib/Interactions/WebDriverTouchActions.php @@ -15,155 +15,179 @@ namespace Facebook\WebDriver\Interactions; -use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen; use Facebook\WebDriver\Interactions\Touch\WebDriverDoubleTapAction; +use Facebook\WebDriver\Interactions\Touch\WebDriverDownAction; use Facebook\WebDriver\Interactions\Touch\WebDriverFlickAction; use Facebook\WebDriver\Interactions\Touch\WebDriverFlickFromElementAction; use Facebook\WebDriver\Interactions\Touch\WebDriverLongPressAction; -use Facebook\WebDriver\Interactions\Touch\WebDriverTapAction; -use Facebook\WebDriver\Interactions\Touch\WebDriverScrollFromElementAction; -use Facebook\WebDriver\Interactions\Touch\WebDriverDownAction; use Facebook\WebDriver\Interactions\Touch\WebDriverMoveAction; use Facebook\WebDriver\Interactions\Touch\WebDriverScrollAction; -use Facebook\WebDriver\WebDriverUpAction; -use Facebook\WebDriver\WebDriverElement; +use Facebook\WebDriver\Interactions\Touch\WebDriverScrollFromElementAction; +use Facebook\WebDriver\Interactions\Touch\WebDriverTapAction; +use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen; use Facebook\WebDriver\WebDriver; +use Facebook\WebDriver\WebDriverElement; +use Facebook\WebDriver\WebDriverUpAction; /** * WebDriver action builder for touch events */ -class WebDriverTouchActions extends WebDriverActions { - - /** - * @var WebDriverTouchScreen - */ - protected $touchScreen; - - public function __construct(WebDriver $driver) { - parent::__construct($driver); - $this->touchScreen = $driver->getTouch(); - } - - /** - * @param WebDriverElement $element - * @return WebDriverTouchActions - */ - public function tap(WebDriverElement $element) { - $this->action->addAction( - new WebDriverTapAction($this->touchScreen, $element) - ); - return $this; - } - - /** - * @param int $x - * @param int $y - * @return WebDriverTouchActions - */ - public function down($x, $y) { - $this->action->addAction( - new WebDriverDownAction($this->touchScreen, $x, $y) - ); - return $this; - } - - /** - * @param int $x - * @param int $y - * @return WebDriverTouchActions - */ - public function up($x, $y) { - $this->action->addAction( - new WebDriverUpAction($this->touchScreen, $x, $y) - ); - return $this; - } - - /** - * @param int $x - * @param int $y - * @return WebDriverTouchActions - */ - public function move($x, $y) { - $this->action->addAction( - new WebDriverMoveAction($this->touchScreen, $x, $y) - ); - return $this; - } - - /** - * @param int $x - * @param int $y - * @return WebDriverTouchActions - */ - public function scroll($x, $y) { - $this->action->addAction( - new WebDriverScrollAction($this->touchScreen, $x, $y) - ); - return $this; - } - - /** - * @param WebDriverElement $element - * @param int $x - * @param int $y - * @return WebDriverTouchActions - */ - public function scrollFromElement(WebDriverElement $element, $x, $y) { - $this->action->addAction( - new WebDriverScrollFromElementAction($this->touchScreen, $element, $x, $y) - ); - return $this; - } - - /** - * @param WebDriverElement $element - * @return WebDriverTouchActions - */ - public function doubleTap(WebDriverElement $element) { - $this->action->addAction( - new WebDriverDoubleTapAction($this->touchScreen, $element) - ); - return $this; - } - - /** - * @param WebDriverElement $element - * @return WebDriverTouchActions - */ - public function longPress(WebDriverElement $element) { - $this->action->addAction( - new WebDriverLongPressAction($this->touchScreen, $element) - ); - return $this; - } - - /** - * @param int $x - * @param int $y - * @return WebDriverTouchActions - */ - public function flick($x, $y) { - $this->action->addAction( - new WebDriverFlickAction($this->touchScreen, $x, $y) - ); - return $this; - } - - /** - * @param WebDriverElement $element - * @param int $x - * @param int $y - * @param int $speed - * @return WebDriverTouchActions - */ - public function flickFromElement(WebDriverElement $element, $x, $y, $speed) { - $this->action->addAction( - new WebDriverFlickFromElementAction( - $this->touchScreen, $element, $x, $y, $speed - ) - ); - return $this; - } - +class WebDriverTouchActions extends WebDriverActions +{ + /** + * @var WebDriverTouchScreen + */ + protected $touchScreen; + + public function __construct(WebDriver $driver) + { + parent::__construct($driver); + $this->touchScreen = $driver->getTouch(); + } + + /** + * @param WebDriverElement $element + * @return WebDriverTouchActions + */ + public function tap(WebDriverElement $element) + { + $this->action->addAction( + new WebDriverTapAction($this->touchScreen, $element) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * @return WebDriverTouchActions + */ + public function down($x, $y) + { + $this->action->addAction( + new WebDriverDownAction($this->touchScreen, $x, $y) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * @return WebDriverTouchActions + */ + public function up($x, $y) + { + $this->action->addAction( + new WebDriverUpAction($this->touchScreen, $x, $y) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * @return WebDriverTouchActions + */ + public function move($x, $y) + { + $this->action->addAction( + new WebDriverMoveAction($this->touchScreen, $x, $y) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * @return WebDriverTouchActions + */ + public function scroll($x, $y) + { + $this->action->addAction( + new WebDriverScrollAction($this->touchScreen, $x, $y) + ); + + return $this; + } + + /** + * @param WebDriverElement $element + * @param int $x + * @param int $y + * @return WebDriverTouchActions + */ + public function scrollFromElement(WebDriverElement $element, $x, $y) + { + $this->action->addAction( + new WebDriverScrollFromElementAction($this->touchScreen, $element, $x, $y) + ); + + return $this; + } + + /** + * @param WebDriverElement $element + * @return WebDriverTouchActions + */ + public function doubleTap(WebDriverElement $element) + { + $this->action->addAction( + new WebDriverDoubleTapAction($this->touchScreen, $element) + ); + + return $this; + } + + /** + * @param WebDriverElement $element + * @return WebDriverTouchActions + */ + public function longPress(WebDriverElement $element) + { + $this->action->addAction( + new WebDriverLongPressAction($this->touchScreen, $element) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * @return WebDriverTouchActions + */ + public function flick($x, $y) + { + $this->action->addAction( + new WebDriverFlickAction($this->touchScreen, $x, $y) + ); + + return $this; + } + + /** + * @param WebDriverElement $element + * @param int $x + * @param int $y + * @param int $speed + * @return WebDriverTouchActions + */ + public function flickFromElement(WebDriverElement $element, $x, $y, $speed) + { + $this->action->addAction( + new WebDriverFlickFromElementAction( + $this->touchScreen, + $element, + $x, + $y, + $speed + ) + ); + + return $this; + } } diff --git a/lib/Internal/WebDriverLocatable.php b/lib/Internal/WebDriverLocatable.php index 1523c35c0..e40c36b57 100644 --- a/lib/Internal/WebDriverLocatable.php +++ b/lib/Internal/WebDriverLocatable.php @@ -18,12 +18,12 @@ use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates; /** - * interface representing basic mouse operations. + * Interface representing basic mouse operations. */ -interface WebDriverLocatable { - - /** - * @return WebDriverCoordinates - */ - public function getCoordinates(); +interface WebDriverLocatable +{ + /** + * @return WebDriverCoordinates + */ + public function getCoordinates(); } diff --git a/lib/JavaScriptExecutor.php b/lib/JavaScriptExecutor.php index 3e0db1302..61aa21b0e 100644 --- a/lib/JavaScriptExecutor.php +++ b/lib/JavaScriptExecutor.php @@ -18,32 +18,31 @@ /** * WebDriver interface implemented by drivers that support JavaScript. */ -interface JavaScriptExecutor { - - /** - * Inject a snippet of JavaScript into the page for execution in the context - * of the currently selected frame. The executed script is assumed to be - * synchronous and the result of evaluating the script will be returned. - * - * @param string $script The script to inject. - * @param array $arguments The arguments of the script. - * @return mixed The return value of the script. - */ - public function executeScript($script, array $arguments = array()); - - /** - * Inject a snippet of JavaScript into the page for asynchronous execution in - * the context of the currently selected frame. - * - * The driver will pass a callback as the last argument to the snippet, and - * block until the callback is invoked. - * - * @see WebDriverExecuteAsyncScriptTestCase - * - * @param string $script The script to inject. - * @param array $arguments The arguments of the script. - * @return mixed The value passed by the script to the callback. - */ - public function executeAsyncScript($script, array $arguments = array()); +interface JavaScriptExecutor +{ + /** + * Inject a snippet of JavaScript into the page for execution in the context + * of the currently selected frame. The executed script is assumed to be + * synchronous and the result of evaluating the script will be returned. + * + * @param string $script The script to inject. + * @param array $arguments The arguments of the script. + * @return mixed The return value of the script. + */ + public function executeScript($script, array $arguments = array()); + /** + * Inject a snippet of JavaScript into the page for asynchronous execution in + * the context of the currently selected frame. + * + * The driver will pass a callback as the last argument to the snippet, and + * block until the callback is invoked. + * + * @see WebDriverExecuteAsyncScriptTestCase + * + * @param string $script The script to inject. + * @param array $arguments The arguments of the script. + * @return mixed The value passed by the script to the callback. + */ + public function executeAsyncScript($script, array $arguments = array()); } diff --git a/lib/Net/URLChecker.php b/lib/Net/URLChecker.php index b41d68c25..3a5d76316 100644 --- a/lib/Net/URLChecker.php +++ b/lib/Net/URLChecker.php @@ -18,64 +18,68 @@ use Exception; use Facebook\WebDriver\Exception\TimeOutException; -class URLChecker { +class URLChecker +{ + const POLL_INTERVAL_MS = 500; + const CONNECT_TIMEOUT_MS = 500; - const POLL_INTERVAL_MS = 500; - const CONNECT_TIMEOUT_MS = 500; + public function waitUntilAvailable($timeout_in_ms, $url) + { + $end = microtime(true) + $timeout_in_ms / 1000; - public function waitUntilAvailable($timeout_in_ms, $url) { - $end = microtime(true) + $timeout_in_ms / 1000; + while ($end > microtime(true)) { + if ($this->getHTTPResponseCode($timeout_in_ms, $url) === 200) { + return $this; + } + usleep(self::POLL_INTERVAL_MS); + } - while ($end > microtime(true)) { - if ($this->getHTTPResponseCode($timeout_in_ms, $url) === 200) { - return $this; - } - usleep(self::POLL_INTERVAL_MS); + throw new TimeOutException(sprintf( + 'Timed out waiting for %s to become available after %d ms.', + $url, + $timeout_in_ms + )); } - throw new TimeOutException(sprintf( - "Timed out waiting for %s to become available after %d ms.", - $url, - $timeout_in_ms - )); - } + public function waitUntilUnavailable($timeout_in_ms, $url) + { + $end = microtime(true) + $timeout_in_ms / 1000; - public function waitUntilUnavailable($timeout_in_ms, $url) { - $end = microtime(true) + $timeout_in_ms / 1000; + while ($end > microtime(true)) { + if ($this->getHTTPResponseCode($timeout_in_ms, $url) !== 200) { + return $this; + } + usleep(self::POLL_INTERVAL_MS); + } - while ($end > microtime(true)) { - if ($this->getHTTPResponseCode($timeout_in_ms, $url) !== 200) { - return $this; - } - usleep(self::POLL_INTERVAL_MS); + throw new TimeOutException(sprintf( + 'Timed out waiting for %s to become unavailable after %d ms.', + $url, + $timeout_in_ms + )); } - throw new TimeOutException(sprintf( - "Timed out waiting for %s to become unavailable after %d ms.", - $url, - $timeout_in_ms - )); - } + private function getHTTPResponseCode($timeout_in_ms, $url) + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS); + // There is a PHP bug in some versions which didn't define the constant. + curl_setopt( + $ch, + 156, // CURLOPT_CONNECTTIMEOUT_MS + self::CONNECT_TIMEOUT_MS + ); + $code = null; + try { + curl_exec($ch); + $info = curl_getinfo($ch); + $code = $info['http_code']; + } catch (Exception $e) { + } + curl_close($ch); - private function getHTTPResponseCode($timeout_in_ms, $url) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS); - // There is a PHP bug in some versions which didn't define the constant. - curl_setopt( - $ch, - 156, // CURLOPT_CONNECTTIMEOUT_MS - self::CONNECT_TIMEOUT_MS - ); - $code = null; - try { - curl_exec($ch); - $info = curl_getinfo($ch); - $code = $info['http_code']; - } catch (Exception $e) { + return $code; } - curl_close($ch); - return $code; - } } diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index ef732ec53..8e30aae14 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -23,271 +23,306 @@ use Facebook\WebDriver\WebDriverCapabilities; use Facebook\WebDriver\WebDriverPlatform; -class DesiredCapabilities implements WebDriverCapabilities { - - private $capabilities; - - public function __construct(array $capabilities = array()) { - $this->capabilities = $capabilities; - } - - /** - * @return string The name of the browser. - */ - public function getBrowserName() { - return $this->get(WebDriverCapabilityType::BROWSER_NAME, ''); - } - - /** - * @param string $browser_name - * @return DesiredCapabilities - */ - public function setBrowserName($browser_name) { - $this->set(WebDriverCapabilityType::BROWSER_NAME, $browser_name); - return $this; - } - - /** - * @return string The version of the browser. - */ - public function getVersion() { - return $this->get(WebDriverCapabilityType::VERSION, ''); - } - - /** - * @param string $version - * @return DesiredCapabilities - */ - public function setVersion($version) { - $this->set(WebDriverCapabilityType::VERSION, $version); - return $this; - } - - /** - * @param string $name - * @return mixed The value of a capability. - */ - public function getCapability($name) { - return $this->get($name); - } - - /** - * @param string $name - * @param mixed $value - * @return DesiredCapabilities - */ - public function setCapability($name, $value) { - $this->set($name, $value); - return $this; - } - - /** - * @return string The name of the platform. - */ - public function getPlatform() { - return $this->get(WebDriverCapabilityType::PLATFORM, ''); - } - - /** - * @param string $platform - * @return DesiredCapabilities - */ - public function setPlatform($platform) { - $this->set(WebDriverCapabilityType::PLATFORM, $platform); - return $this; - } - - /** - * @param string $capability_name - * @return bool Whether the value is not null and not false. - */ - public function is($capability_name) { - return (bool) $this->get($capability_name); - } - - /** - * @return bool Whether javascript is enabled. - */ - public function isJavascriptEnabled() { - return $this->get(WebDriverCapabilityType::JAVASCRIPT_ENABLED, false); - } - - /** - * This is a htmlUnit-only option. - * - * @param bool $enabled - * @throws Exception - * @return DesiredCapabilities - * @see https://code.google.com/p/selenium/wiki/DesiredCapabilities#Read-write_capabilities - */ - public function setJavascriptEnabled($enabled) { - $browser = $this->getBrowserName(); - if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) { - throw new Exception( - 'isJavascriptEnable() is a htmlunit-only option. '. - 'See https://code.google.com/p/selenium/wiki/DesiredCapabilities#Read-write_capabilities.' - ); +class DesiredCapabilities implements WebDriverCapabilities +{ + private $capabilities; + + public function __construct(array $capabilities = array()) + { + $this->capabilities = $capabilities; + } + + /** + * @return string The name of the browser. + */ + public function getBrowserName() + { + return $this->get(WebDriverCapabilityType::BROWSER_NAME, ''); + } + + /** + * @param string $browser_name + * @return DesiredCapabilities + */ + public function setBrowserName($browser_name) + { + $this->set(WebDriverCapabilityType::BROWSER_NAME, $browser_name); + + return $this; + } + + /** + * @return string The version of the browser. + */ + public function getVersion() + { + return $this->get(WebDriverCapabilityType::VERSION, ''); + } + + /** + * @param string $version + * @return DesiredCapabilities + */ + public function setVersion($version) + { + $this->set(WebDriverCapabilityType::VERSION, $version); + + return $this; + } + + /** + * @param string $name + * @return mixed The value of a capability. + */ + public function getCapability($name) + { + return $this->get($name); } - $this->set(WebDriverCapabilityType::JAVASCRIPT_ENABLED, $enabled); - return $this; - } - - /** - * @return array - */ - public function toArray() { - if (isset($this->capabilities[ChromeOptions::CAPABILITY]) && - $this->capabilities[ChromeOptions::CAPABILITY] instanceof ChromeOptions) { - $this->capabilities[ChromeOptions::CAPABILITY] = - $this->capabilities[ChromeOptions::CAPABILITY]->toArray(); + /** + * @param string $name + * @param mixed $value + * @return DesiredCapabilities + */ + public function setCapability($name, $value) + { + $this->set($name, $value); + + return $this; + } + + /** + * @return string The name of the platform. + */ + public function getPlatform() + { + return $this->get(WebDriverCapabilityType::PLATFORM, ''); } - if (isset($this->capabilities[FirefoxDriver::PROFILE]) && - $this->capabilities[FirefoxDriver::PROFILE] instanceof FirefoxProfile) { - $this->capabilities[FirefoxDriver::PROFILE] = - $this->capabilities[FirefoxDriver::PROFILE]->encode(); + /** + * @param string $platform + * @return DesiredCapabilities + */ + public function setPlatform($platform) + { + $this->set(WebDriverCapabilityType::PLATFORM, $platform); + + return $this; } - return $this->capabilities; - } - - /** - * @param string $key - * @param mixed $value - * @return DesiredCapabilities - */ - private function set($key, $value) { - $this->capabilities[$key] = $value; - return $this; - } - - /** - * @param string $key - * @param mixed $default - * @return mixed - */ - private function get($key, $default = null) { - return isset($this->capabilities[$key]) - ? $this->capabilities[$key] - : $default; - } - - /** - * @return DesiredCapabilities - */ - public static function android() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function chrome() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function firefox() { - $caps = new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - - // disable the "Reader View" help tooltip, which can hide elements in the window.document - $profile = new FirefoxProfile(); - $profile->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false); - $caps->setCapability(FirefoxDriver::PROFILE, $profile); - - return $caps; - } - - /** - * @return DesiredCapabilities - */ - public static function htmlUnit() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function htmlUnitWithJS() { - $caps = new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - return $caps->setJavascriptEnabled(true); - } - - /** - * @return DesiredCapabilities - */ - public static function internetExplorer() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function iphone() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function ipad() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function opera() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function safari() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - } - - /** - * @return DesiredCapabilities - */ - public static function phantomjs() { - return new DesiredCapabilities(array( - WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS, - WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); - } + /** + * @param string $capability_name + * @return bool Whether the value is not null and not false. + */ + public function is($capability_name) + { + return (bool) $this->get($capability_name); + } + + /** + * @return bool Whether javascript is enabled. + */ + public function isJavascriptEnabled() + { + return $this->get(WebDriverCapabilityType::JAVASCRIPT_ENABLED, false); + } + + /** + * This is a htmlUnit-only option. + * + * @param bool $enabled + * @throws Exception + * @return DesiredCapabilities + * @see https://code.google.com/p/selenium/wiki/DesiredCapabilities#Read-write_capabilities + */ + public function setJavascriptEnabled($enabled) + { + $browser = $this->getBrowserName(); + if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) { + throw new Exception( + 'isJavascriptEnable() is a htmlunit-only option. ' . + 'See https://code.google.com/p/selenium/wiki/DesiredCapabilities#Read-write_capabilities.' + ); + } + + $this->set(WebDriverCapabilityType::JAVASCRIPT_ENABLED, $enabled); + + return $this; + } + + /** + * @return array + */ + public function toArray() + { + if (isset($this->capabilities[ChromeOptions::CAPABILITY]) && + $this->capabilities[ChromeOptions::CAPABILITY] instanceof ChromeOptions + ) { + $this->capabilities[ChromeOptions::CAPABILITY] = + $this->capabilities[ChromeOptions::CAPABILITY]->toArray(); + } + + if (isset($this->capabilities[FirefoxDriver::PROFILE]) && + $this->capabilities[FirefoxDriver::PROFILE] instanceof FirefoxProfile + ) { + $this->capabilities[FirefoxDriver::PROFILE] = + $this->capabilities[FirefoxDriver::PROFILE]->encode(); + } + + return $this->capabilities; + } + + /** + * @param string $key + * @param mixed $value + * @return DesiredCapabilities + */ + private function set($key, $value) + { + $this->capabilities[$key] = $value; + + return $this; + } + + /** + * @param string $key + * @param mixed $default + * @return mixed + */ + private function get($key, $default = null) + { + return isset($this->capabilities[$key]) + ? $this->capabilities[$key] + : $default; + } + + /** + * @return DesiredCapabilities + */ + public static function android() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function chrome() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function firefox() + { + $caps = new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + + // disable the "Reader View" help tooltip, which can hide elements in the window.document + $profile = new FirefoxProfile(); + $profile->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false); + $caps->setCapability(FirefoxDriver::PROFILE, $profile); + + return $caps; + } + + /** + * @return DesiredCapabilities + */ + public static function htmlUnit() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function htmlUnitWithJS() + { + $caps = new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + + return $caps->setJavascriptEnabled(true); + } + + /** + * @return DesiredCapabilities + */ + public static function internetExplorer() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function iphone() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function ipad() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function opera() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function safari() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + } + + /** + * @return DesiredCapabilities + */ + public static function phantomjs() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + )); + } } diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index 18e9fb37b..e2ce958b5 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -18,154 +18,129 @@ /** * This list of command defined in the WebDriver json wire protocol. */ -class DriverCommand { - const GET_ALL_SESSIONS = "getAllSessions"; - const GET_CAPABILITIES = "getCapabilities"; - const NEW_SESSION = "newSession"; - - const STATUS = "status"; - - const CLOSE = "close"; - const QUIT = "quit"; - - const GET = "get"; - const GO_BACK = "goBack"; - const GO_FORWARD = "goForward"; - const REFRESH = "refresh"; - - const ADD_COOKIE = "addCookie"; - const GET_ALL_COOKIES = "getCookies"; - const DELETE_COOKIE = "deleteCookie"; - const DELETE_ALL_COOKIES = "deleteAllCookies"; - - const FIND_ELEMENT = "findElement"; - const FIND_ELEMENTS = "findElements"; - const FIND_CHILD_ELEMENT = "findChildElement"; - const FIND_CHILD_ELEMENTS = "findChildElements"; - - const CLEAR_ELEMENT = "clearElement"; - const CLICK_ELEMENT = "clickElement"; - const SEND_KEYS_TO_ELEMENT = "sendKeysToElement"; - const SEND_KEYS_TO_ACTIVE_ELEMENT = "sendKeysToActiveElement"; - const SUBMIT_ELEMENT = "submitElement"; - const UPLOAD_FILE = "uploadFile"; - - const GET_CURRENT_WINDOW_HANDLE = "getCurrentWindowHandle"; - const GET_WINDOW_HANDLES = "getWindowHandles"; - - const GET_CURRENT_CONTEXT_HANDLE = "getCurrentContextHandle"; - const GET_CONTEXT_HANDLES = "getContextHandles"; - - // Switching between to window/frame/iframe - const SWITCH_TO_WINDOW = "switchToWindow"; - const SWITCH_TO_CONTEXT = "switchToContext"; - const SWITCH_TO_FRAME = "switchToFrame"; - const SWITCH_TO_PARENT_FRAME = "switchToParentFrame"; - const GET_ACTIVE_ELEMENT = "getActiveElement"; - - // Information of the page - const GET_CURRENT_URL = "getCurrentUrl"; - const GET_PAGE_SOURCE = "getPageSource"; - const GET_TITLE = "getTitle"; - - // Javascript API - const EXECUTE_SCRIPT = "executeScript"; - const EXECUTE_ASYNC_SCRIPT = "executeAsyncScript"; - - // API getting information from an element. - const GET_ELEMENT_TEXT = "getElementText"; - const GET_ELEMENT_TAG_NAME = "getElementTagName"; - const IS_ELEMENT_SELECTED = "isElementSelected"; - const IS_ELEMENT_ENABLED = "isElementEnabled"; - const IS_ELEMENT_DISPLAYED = "isElementDisplayed"; - const GET_ELEMENT_LOCATION = "getElementLocation"; - const GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = - "getElementLocationOnceScrolledIntoView"; - const GET_ELEMENT_SIZE = "getElementSize"; - const GET_ELEMENT_ATTRIBUTE = "getElementAttribute"; - const GET_ELEMENT_VALUE_OF_CSS_PROPERTY = "getElementValueOfCssProperty"; - const ELEMENT_EQUALS = "elementEquals"; - - const SCREENSHOT = "screenshot"; - - // Alert API - const ACCEPT_ALERT = "acceptAlert"; - const DISMISS_ALERT = "dismissAlert"; - const GET_ALERT_TEXT = "getAlertText"; - const SET_ALERT_VALUE = "setAlertValue"; - - // Timeout API - const SET_TIMEOUT = "setTimeout"; - const IMPLICITLY_WAIT = "implicitlyWait"; - const SET_SCRIPT_TIMEOUT = "setScriptTimeout"; - - const EXECUTE_SQL = "executeSQL"; - const GET_LOCATION = "getLocation"; - const SET_LOCATION = "setLocation"; - const GET_APP_CACHE = "getAppCache"; - const GET_APP_CACHE_STATUS = "getStatus"; - const CLEAR_APP_CACHE = "clearAppCache"; - const IS_BROWSER_ONLINE = "isBrowserOnline"; - const SET_BROWSER_ONLINE = "setBrowserOnline"; - - const GET_LOCAL_STORAGE_ITEM = "getLocalStorageItem"; - const GET_LOCAL_STORAGE_KEYS = "getLocalStorageKeys"; - const SET_LOCAL_STORAGE_ITEM = "setLocalStorageItem"; - const REMOVE_LOCAL_STORAGE_ITEM = "removeLocalStorageItem"; - const CLEAR_LOCAL_STORAGE = "clearLocalStorage"; - const GET_LOCAL_STORAGE_SIZE = "getLocalStorageSize"; - - const GET_SESSION_STORAGE_ITEM = "getSessionStorageItem"; - const GET_SESSION_STORAGE_KEYS = "getSessionStorageKey"; - const SET_SESSION_STORAGE_ITEM = "setSessionStorageItem"; - const REMOVE_SESSION_STORAGE_ITEM = "removeSessionStorageItem"; - const CLEAR_SESSION_STORAGE = "clearSessionStorage"; - const GET_SESSION_STORAGE_SIZE = "getSessionStorageSize"; - - const SET_SCREEN_ORIENTATION = "setScreenOrientation"; - const GET_SCREEN_ORIENTATION = "getScreenOrientation"; - - // These belong to the Advanced user interactions - an element is optional for these commands. - const CLICK = "mouseClick"; - const DOUBLE_CLICK = "mouseDoubleClick"; - const MOUSE_DOWN = "mouseButtonDown"; - const MOUSE_UP = "mouseButtonUp"; - const MOVE_TO = "mouseMoveTo"; - - // Those allow interactions with the Input Methods installed on the system. - const IME_GET_AVAILABLE_ENGINES = "imeGetAvailableEngines"; - const IME_GET_ACTIVE_ENGINE = "imeGetActiveEngine"; - const IME_IS_ACTIVATED = "imeIsActivated"; - const IME_DEACTIVATE = "imeDeactivate"; - const IME_ACTIVATE_ENGINE = "imeActivateEngine"; - - // These belong to the Advanced Touch API - const TOUCH_SINGLE_TAP = "touchSingleTap"; - const TOUCH_DOWN = "touchDown"; - const TOUCH_UP = "touchUp"; - const TOUCH_MOVE = "touchMove"; - const TOUCH_SCROLL = "touchScroll"; - const TOUCH_DOUBLE_TAP = "touchDoubleTap"; - const TOUCH_LONG_PRESS = "touchLongPress"; - const TOUCH_FLICK = "touchFlick"; - - // Window API (beta) - const SET_WINDOW_SIZE = "setWindowSize"; - const SET_WINDOW_POSITION = "setWindowPosition"; - const GET_WINDOW_SIZE = "getWindowSize"; - const GET_WINDOW_POSITION = "getWindowPosition"; - const MAXIMIZE_WINDOW = "maximizeWindow"; - - // Logging API - const GET_AVAILABLE_LOG_TYPES = "getAvailableLogTypes"; - const GET_LOG = "getLog"; - const GET_SESSION_LOGS = "getSessionLogs"; - - // Mobile API - const GET_NETWORK_CONNECTION = "getNetworkConnection"; - const SET_NETWORK_CONNECTION = "setNetworkConnection"; - - private function __construct() - { - } +class DriverCommand +{ + const GET_ALL_SESSIONS = 'getAllSessions'; + const GET_CAPABILITIES = 'getCapabilities'; + const NEW_SESSION = 'newSession'; + const STATUS = 'status'; + const CLOSE = 'close'; + const QUIT = 'quit'; + const GET = 'get'; + const GO_BACK = 'goBack'; + const GO_FORWARD = 'goForward'; + const REFRESH = 'refresh'; + const ADD_COOKIE = 'addCookie'; + const GET_ALL_COOKIES = 'getCookies'; + const DELETE_COOKIE = 'deleteCookie'; + const DELETE_ALL_COOKIES = 'deleteAllCookies'; + const FIND_ELEMENT = 'findElement'; + const FIND_ELEMENTS = 'findElements'; + const FIND_CHILD_ELEMENT = 'findChildElement'; + const FIND_CHILD_ELEMENTS = 'findChildElements'; + const CLEAR_ELEMENT = 'clearElement'; + const CLICK_ELEMENT = 'clickElement'; + const SEND_KEYS_TO_ELEMENT = 'sendKeysToElement'; + const SEND_KEYS_TO_ACTIVE_ELEMENT = 'sendKeysToActiveElement'; + const SUBMIT_ELEMENT = 'submitElement'; + const UPLOAD_FILE = 'uploadFile'; + const GET_CURRENT_WINDOW_HANDLE = 'getCurrentWindowHandle'; + const GET_WINDOW_HANDLES = 'getWindowHandles'; + const GET_CURRENT_CONTEXT_HANDLE = 'getCurrentContextHandle'; + const GET_CONTEXT_HANDLES = 'getContextHandles'; + // Switching between to window/frame/iframe + const SWITCH_TO_WINDOW = 'switchToWindow'; + const SWITCH_TO_CONTEXT = 'switchToContext'; + const SWITCH_TO_FRAME = 'switchToFrame'; + const SWITCH_TO_PARENT_FRAME = 'switchToParentFrame'; + const GET_ACTIVE_ELEMENT = 'getActiveElement'; + // Information of the page + const GET_CURRENT_URL = 'getCurrentUrl'; + const GET_PAGE_SOURCE = 'getPageSource'; + const GET_TITLE = 'getTitle'; + // Javascript API + const EXECUTE_SCRIPT = 'executeScript'; + const EXECUTE_ASYNC_SCRIPT = 'executeAsyncScript'; + // API getting information from an element. + const GET_ELEMENT_TEXT = 'getElementText'; + const GET_ELEMENT_TAG_NAME = 'getElementTagName'; + const IS_ELEMENT_SELECTED = 'isElementSelected'; + const IS_ELEMENT_ENABLED = 'isElementEnabled'; + const IS_ELEMENT_DISPLAYED = 'isElementDisplayed'; + const GET_ELEMENT_LOCATION = 'getElementLocation'; + const GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = 'getElementLocationOnceScrolledIntoView'; + const GET_ELEMENT_SIZE = 'getElementSize'; + const GET_ELEMENT_ATTRIBUTE = 'getElementAttribute'; + const GET_ELEMENT_VALUE_OF_CSS_PROPERTY = 'getElementValueOfCssProperty'; + const ELEMENT_EQUALS = 'elementEquals'; + const SCREENSHOT = 'screenshot'; + // Alert API + const ACCEPT_ALERT = 'acceptAlert'; + const DISMISS_ALERT = 'dismissAlert'; + const GET_ALERT_TEXT = 'getAlertText'; + const SET_ALERT_VALUE = 'setAlertValue'; + // Timeout API + const SET_TIMEOUT = 'setTimeout'; + const IMPLICITLY_WAIT = 'implicitlyWait'; + const SET_SCRIPT_TIMEOUT = 'setScriptTimeout'; + const EXECUTE_SQL = 'executeSQL'; + const GET_LOCATION = 'getLocation'; + const SET_LOCATION = 'setLocation'; + const GET_APP_CACHE = 'getAppCache'; + const GET_APP_CACHE_STATUS = 'getStatus'; + const CLEAR_APP_CACHE = 'clearAppCache'; + const IS_BROWSER_ONLINE = 'isBrowserOnline'; + const SET_BROWSER_ONLINE = 'setBrowserOnline'; + const GET_LOCAL_STORAGE_ITEM = 'getLocalStorageItem'; + const GET_LOCAL_STORAGE_KEYS = 'getLocalStorageKeys'; + const SET_LOCAL_STORAGE_ITEM = 'setLocalStorageItem'; + const REMOVE_LOCAL_STORAGE_ITEM = 'removeLocalStorageItem'; + const CLEAR_LOCAL_STORAGE = 'clearLocalStorage'; + const GET_LOCAL_STORAGE_SIZE = 'getLocalStorageSize'; + const GET_SESSION_STORAGE_ITEM = 'getSessionStorageItem'; + const GET_SESSION_STORAGE_KEYS = 'getSessionStorageKey'; + const SET_SESSION_STORAGE_ITEM = 'setSessionStorageItem'; + const REMOVE_SESSION_STORAGE_ITEM = 'removeSessionStorageItem'; + const CLEAR_SESSION_STORAGE = 'clearSessionStorage'; + const GET_SESSION_STORAGE_SIZE = 'getSessionStorageSize'; + const SET_SCREEN_ORIENTATION = 'setScreenOrientation'; + const GET_SCREEN_ORIENTATION = 'getScreenOrientation'; + // These belong to the Advanced user interactions - an element is optional for these commands. + const CLICK = 'mouseClick'; + const DOUBLE_CLICK = 'mouseDoubleClick'; + const MOUSE_DOWN = 'mouseButtonDown'; + const MOUSE_UP = 'mouseButtonUp'; + const MOVE_TO = 'mouseMoveTo'; + // Those allow interactions with the Input Methods installed on the system. + const IME_GET_AVAILABLE_ENGINES = 'imeGetAvailableEngines'; + const IME_GET_ACTIVE_ENGINE = 'imeGetActiveEngine'; + const IME_IS_ACTIVATED = 'imeIsActivated'; + const IME_DEACTIVATE = 'imeDeactivate'; + const IME_ACTIVATE_ENGINE = 'imeActivateEngine'; + // These belong to the Advanced Touch API + const TOUCH_SINGLE_TAP = 'touchSingleTap'; + const TOUCH_DOWN = 'touchDown'; + const TOUCH_UP = 'touchUp'; + const TOUCH_MOVE = 'touchMove'; + const TOUCH_SCROLL = 'touchScroll'; + const TOUCH_DOUBLE_TAP = 'touchDoubleTap'; + const TOUCH_LONG_PRESS = 'touchLongPress'; + const TOUCH_FLICK = 'touchFlick'; + // Window API (beta) + const SET_WINDOW_SIZE = 'setWindowSize'; + const SET_WINDOW_POSITION = 'setWindowPosition'; + const GET_WINDOW_SIZE = 'getWindowSize'; + const GET_WINDOW_POSITION = 'getWindowPosition'; + const MAXIMIZE_WINDOW = 'maximizeWindow'; + // Logging API + const GET_AVAILABLE_LOG_TYPES = 'getAvailableLogTypes'; + const GET_LOG = 'getLog'; + const GET_SESSION_LOGS = 'getSessionLogs'; + // Mobile API + const GET_NETWORK_CONNECTION = 'getNetworkConnection'; + const SET_NETWORK_CONNECTION = 'setNetworkConnection'; + + private function __construct() + { + } } diff --git a/lib/Remote/ExecuteMethod.php b/lib/Remote/ExecuteMethod.php index ff13c58fe..38ad319e7 100644 --- a/lib/Remote/ExecuteMethod.php +++ b/lib/Remote/ExecuteMethod.php @@ -15,12 +15,12 @@ namespace Facebook\WebDriver\Remote; -interface ExecuteMethod { - - /** - * @param string $command_name - * @param array $parameters - * @return WebDriverResponse - */ - public function execute($command_name, array $parameters = array()); +interface ExecuteMethod +{ + /** + * @param string $command_name + * @param array $parameters + * @return WebDriverResponse + */ + public function execute($command_name, array $parameters = array()); } diff --git a/lib/Remote/FileDetector.php b/lib/Remote/FileDetector.php index a6e52f48d..483df049c 100644 --- a/lib/Remote/FileDetector.php +++ b/lib/Remote/FileDetector.php @@ -15,15 +15,15 @@ namespace Facebook\WebDriver\Remote; -interface FileDetector { - - /** - * Try to detect whether the given $file is a file or not. Return the path - * of the file. Otherwise, return null. - * - * @param string $file - * - * @return null|string The path of the file. - */ - public function getLocalFile($file); +interface FileDetector +{ + /** + * Try to detect whether the given $file is a file or not. Return the path + * of the file. Otherwise, return null. + * + * @param string $file + * + * @return null|string The path of the file. + */ + public function getLocalFile($file); } diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index ebd47357e..37670610d 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -15,287 +15,355 @@ namespace Facebook\WebDriver\Remote; +use BadMethodCallException; use Facebook\WebDriver\Exception\WebDriverException; use Facebook\WebDriver\WebDriverCommandExecutor; use InvalidArgumentException; -use BadMethodCallException; /** * Command executor talking to the standalone server via HTTP. */ -class HttpCommandExecutor implements WebDriverCommandExecutor { +class HttpCommandExecutor implements WebDriverCommandExecutor +{ + /** + * @see + * http://code.google.com/p/selenium/wiki/JsonWireProtocol#Command_Reference + */ + protected static $commands = array( + DriverCommand::ACCEPT_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/accept_alert'), + DriverCommand::ADD_COOKIE => array('method' => 'POST', 'url' => '/session/:sessionId/cookie'), + DriverCommand::CLEAR_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'), + DriverCommand::CLICK_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'), + DriverCommand::CLOSE => array('method' => 'DELETE', 'url' => '/session/:sessionId/window'), + DriverCommand::DELETE_ALL_COOKIES => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie'), + DriverCommand::DELETE_COOKIE => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'), + DriverCommand::DISMISS_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'), + DriverCommand::ELEMENT_EQUALS => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/equals/:other', + ), + DriverCommand::FIND_CHILD_ELEMENT => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/element/:id/element', + ), + DriverCommand::FIND_CHILD_ELEMENTS => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/element/:id/elements', + ), + DriverCommand::EXECUTE_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute'), + DriverCommand::EXECUTE_ASYNC_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute_async'), + DriverCommand::FIND_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element'), + DriverCommand::FIND_ELEMENTS => array('method' => 'POST', 'url' => '/session/:sessionId/elements'), + DriverCommand::SWITCH_TO_FRAME => array('method' => 'POST', 'url' => '/session/:sessionId/frame'), + DriverCommand::SWITCH_TO_WINDOW => array('method' => 'POST', 'url' => '/session/:sessionId/window'), + DriverCommand::GET => array('method' => 'POST', 'url' => '/session/:sessionId/url'), + DriverCommand::GET_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/active'), + DriverCommand::GET_ALERT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/alert_text'), + DriverCommand::GET_ALL_COOKIES => array('method' => 'GET', 'url' => '/session/:sessionId/cookie'), + DriverCommand::GET_ALL_SESSIONS => array('method' => 'GET', 'url' => '/sessions'), + DriverCommand::GET_AVAILABLE_LOG_TYPES => array('method' => 'GET', 'url' => '/session/:sessionId/log/types'), + DriverCommand::GET_CURRENT_URL => array('method' => 'GET', 'url' => '/session/:sessionId/url'), + DriverCommand::GET_CURRENT_WINDOW_HANDLE => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/window_handle', + ), + DriverCommand::GET_ELEMENT_ATTRIBUTE => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/attribute/:name', + ), + DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/css/:propertyName', + ), + DriverCommand::GET_ELEMENT_LOCATION => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/location', + ), + DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/location_in_view', + ), + DriverCommand::GET_ELEMENT_SIZE => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'), + DriverCommand::GET_ELEMENT_TAG_NAME => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/name', + ), + DriverCommand::GET_ELEMENT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'), + DriverCommand::GET_LOG => array('method' => 'POST', 'url' => '/session/:sessionId/log'), + DriverCommand::GET_PAGE_SOURCE => array('method' => 'GET', 'url' => '/session/:sessionId/source'), + DriverCommand::GET_SCREEN_ORIENTATION => array('method' => 'GET', 'url' => '/session/:sessionId/orientation'), + DriverCommand::GET_CAPABILITIES => array('method' => 'GET', 'url' => '/session/:sessionId'), + DriverCommand::GET_TITLE => array('method' => 'GET', 'url' => '/session/:sessionId/title'), + DriverCommand::GET_WINDOW_HANDLES => array('method' => 'GET', 'url' => '/session/:sessionId/window_handles'), + DriverCommand::GET_WINDOW_POSITION => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/window/:windowHandle/position', + ), + DriverCommand::GET_WINDOW_SIZE => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/window/:windowHandle/size', + ), + DriverCommand::GO_BACK => array('method' => 'POST', 'url' => '/session/:sessionId/back'), + DriverCommand::GO_FORWARD => array('method' => 'POST', 'url' => '/session/:sessionId/forward'), + DriverCommand::IS_ELEMENT_DISPLAYED => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/displayed', + ), + DriverCommand::IS_ELEMENT_ENABLED => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/enabled', + ), + DriverCommand::IS_ELEMENT_SELECTED => array( + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/selected', + ), + DriverCommand::MAXIMIZE_WINDOW => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/window/:windowHandle/maximize', + ), + DriverCommand::MOUSE_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/buttondown'), + DriverCommand::MOUSE_UP => array('method' => 'POST', 'url' => '/session/:sessionId/buttonup'), + DriverCommand::CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/click'), + DriverCommand::DOUBLE_CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/doubleclick'), + DriverCommand::MOVE_TO => array('method' => 'POST', 'url' => '/session/:sessionId/moveto'), + DriverCommand::NEW_SESSION => array('method' => 'POST', 'url' => '/session'), + DriverCommand::QUIT => array('method' => 'DELETE', 'url' => '/session/:sessionId'), + DriverCommand::REFRESH => array('method' => 'POST', 'url' => '/session/:sessionId/refresh'), + DriverCommand::UPLOAD_FILE => array('method' => 'POST', 'url' => '/session/:sessionId/file'), // undocumented + DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/keys'), + DriverCommand::SET_ALERT_VALUE => array('method' => 'POST', 'url' => '/session/:sessionId/alert_text'), + DriverCommand::SEND_KEYS_TO_ELEMENT => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/element/:id/value', + ), + DriverCommand::IMPLICITLY_WAIT => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/timeouts/implicit_wait', + ), + DriverCommand::SET_SCREEN_ORIENTATION => array('method' => 'POST', 'url' => '/session/:sessionId/orientation'), + DriverCommand::SET_TIMEOUT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts'), + DriverCommand::SET_SCRIPT_TIMEOUT => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/timeouts/async_script', + ), + DriverCommand::SET_WINDOW_POSITION => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/window/:windowHandle/position', + ), + DriverCommand::SET_WINDOW_SIZE => array( + 'method' => 'POST', + 'url' => '/session/:sessionId/window/:windowHandle/size', + ), + DriverCommand::SUBMIT_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'), + DriverCommand::SCREENSHOT => array('method' => 'GET', 'url' => '/session/:sessionId/screenshot'), + DriverCommand::TOUCH_SINGLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/click'), + DriverCommand::TOUCH_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/touch/down'), + DriverCommand::TOUCH_DOUBLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'), + DriverCommand::TOUCH_FLICK => array('method' => 'POST', 'url' => '/session/:sessionId/touch/flick'), + DriverCommand::TOUCH_LONG_PRESS => array('method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'), + DriverCommand::TOUCH_MOVE => array('method' => 'POST', 'url' => '/session/:sessionId/touch/move'), + DriverCommand::TOUCH_SCROLL => array('method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'), + DriverCommand::TOUCH_UP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/up'), + ); + /** + * @var string + */ + protected $url; + /** + * @var resource + */ + protected $curl; - /** - * @see - * http://code.google.com/p/selenium/wiki/JsonWireProtocol#Command_Reference - */ - protected static $commands = array( - DriverCommand::ACCEPT_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/accept_alert'), - DriverCommand::ADD_COOKIE => array('method' => 'POST', 'url' => '/session/:sessionId/cookie'), - DriverCommand::CLEAR_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'), - DriverCommand::CLICK_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'), - DriverCommand::CLOSE => array('method' => 'DELETE', 'url' => '/session/:sessionId/window'), - DriverCommand::DELETE_ALL_COOKIES => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie'), - DriverCommand::DELETE_COOKIE => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'), - DriverCommand::DISMISS_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'), - DriverCommand::ELEMENT_EQUALS => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/equals/:other'), - DriverCommand::FIND_CHILD_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/element'), - DriverCommand::FIND_CHILD_ELEMENTS => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/elements'), - DriverCommand::EXECUTE_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute'), - DriverCommand::EXECUTE_ASYNC_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute_async'), - DriverCommand::FIND_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element'), - DriverCommand::FIND_ELEMENTS => array('method' => 'POST', 'url' => '/session/:sessionId/elements'), - DriverCommand::SWITCH_TO_FRAME => array('method' => 'POST', 'url' => '/session/:sessionId/frame'), - DriverCommand::SWITCH_TO_WINDOW => array('method' => 'POST', 'url' => '/session/:sessionId/window'), - DriverCommand::GET => array('method' => 'POST', 'url' => '/session/:sessionId/url'), - DriverCommand::GET_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/active'), - DriverCommand::GET_ALERT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/alert_text'), - DriverCommand::GET_ALL_COOKIES => array('method' => 'GET', 'url' => '/session/:sessionId/cookie'), - DriverCommand::GET_ALL_SESSIONS => array('method' => 'GET', 'url' => '/sessions'), - DriverCommand::GET_AVAILABLE_LOG_TYPES => array('method' => 'GET', 'url' => '/session/:sessionId/log/types'), - DriverCommand::GET_CURRENT_URL => array('method' => 'GET', 'url' => '/session/:sessionId/url'), - DriverCommand::GET_CURRENT_WINDOW_HANDLE => array('method' => 'GET', 'url' => '/session/:sessionId/window_handle'), - DriverCommand::GET_ELEMENT_ATTRIBUTE => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/attribute/:name'), - DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/css/:propertyName'), - DriverCommand::GET_ELEMENT_LOCATION => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/location'), - DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/location_in_view'), - DriverCommand::GET_ELEMENT_SIZE => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'), - DriverCommand::GET_ELEMENT_TAG_NAME => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/name'), - DriverCommand::GET_ELEMENT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'), - DriverCommand::GET_LOG => array('method' => 'POST', 'url' => '/session/:sessionId/log'), - DriverCommand::GET_PAGE_SOURCE => array('method' => 'GET', 'url' => '/session/:sessionId/source'), - DriverCommand::GET_SCREEN_ORIENTATION => array('method' => 'GET', 'url' => '/session/:sessionId/orientation'), - DriverCommand::GET_CAPABILITIES => array('method' => 'GET', 'url' => '/session/:sessionId'), - DriverCommand::GET_TITLE => array('method' => 'GET', 'url' => '/session/:sessionId/title'), - DriverCommand::GET_WINDOW_HANDLES => array('method' => 'GET', 'url' => '/session/:sessionId/window_handles'), - DriverCommand::GET_WINDOW_POSITION => array('method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/position'), - DriverCommand::GET_WINDOW_SIZE => array('method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/size'), - DriverCommand::GO_BACK => array('method' => 'POST', 'url' => '/session/:sessionId/back'), - DriverCommand::GO_FORWARD => array('method' => 'POST', 'url' => '/session/:sessionId/forward'), - DriverCommand::IS_ELEMENT_DISPLAYED=> array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/displayed'), - DriverCommand::IS_ELEMENT_ENABLED=> array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/enabled'), - DriverCommand::IS_ELEMENT_SELECTED=> array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/selected'), - DriverCommand::MAXIMIZE_WINDOW => array('method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/maximize'), - DriverCommand::MOUSE_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/buttondown'), - DriverCommand::MOUSE_UP => array('method' => 'POST', 'url' => '/session/:sessionId/buttonup'), - DriverCommand::CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/click'), - DriverCommand::DOUBLE_CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/doubleclick'), - DriverCommand::MOVE_TO => array('method' => 'POST', 'url' => '/session/:sessionId/moveto'), - DriverCommand::NEW_SESSION => array('method' => 'POST', 'url' => '/session'), - DriverCommand::QUIT => array('method' => 'DELETE', 'url' => '/session/:sessionId'), - DriverCommand::REFRESH => array('method' => 'POST', 'url' => '/session/:sessionId/refresh'), - DriverCommand::UPLOAD_FILE => array('method' => 'POST', 'url' => '/session/:sessionId/file'), // undocumented - DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/keys'), - DriverCommand::SET_ALERT_VALUE => array('method' => 'POST', 'url' => '/session/:sessionId/alert_text'), - DriverCommand::SEND_KEYS_TO_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/value'), - DriverCommand::IMPLICITLY_WAIT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts/implicit_wait'), - DriverCommand::SET_SCREEN_ORIENTATION => array('method' => 'POST', 'url' => '/session/:sessionId/orientation'), - DriverCommand::SET_TIMEOUT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts'), - DriverCommand::SET_SCRIPT_TIMEOUT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts/async_script'), - DriverCommand::SET_WINDOW_POSITION => array('method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/position'), - DriverCommand::SET_WINDOW_SIZE => array('method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/size'), - DriverCommand::SUBMIT_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'), - DriverCommand::SCREENSHOT => array('method' => 'GET', 'url' => '/session/:sessionId/screenshot'), - DriverCommand::TOUCH_SINGLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/click'), - DriverCommand::TOUCH_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/touch/down'), - DriverCommand::TOUCH_DOUBLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'), - DriverCommand::TOUCH_FLICK => array('method' => 'POST', 'url' => '/session/:sessionId/touch/flick'), - DriverCommand::TOUCH_LONG_PRESS => array('method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'), - DriverCommand::TOUCH_MOVE => array('method' => 'POST', 'url' => '/session/:sessionId/touch/move'), - DriverCommand::TOUCH_SCROLL => array('method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'), - DriverCommand::TOUCH_UP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/up'), - ); + /** + * @param string $url + * @param string|null $http_proxy + * @param int|null $http_proxy_port + */ + public function __construct($url, $http_proxy = null, $http_proxy_port = null) + { + $this->url = $url; + $this->curl = curl_init(); - /** - * @var string - */ - protected $url; - /** - * @var resource - */ - protected $curl; + if (!empty($http_proxy)) { + curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy); + if (!empty($http_proxy_port)) { + curl_setopt($this->curl, CURLOPT_PROXYPORT, $http_proxy_port); + } + } - /** - * @param string $url - * @param string|null $http_proxy - * @param int|null $http_proxy_port - */ - public function __construct($url, $http_proxy = null, $http_proxy_port = null) { - $this->url = $url; - $this->curl = curl_init(); + // Get credentials from $url (if any) + $matches = null; + if (preg_match("/^(https?:\/\/)(.*):(.*)@(.*?)/U", $url, $matches)) { + $this->url = $matches[1] . $matches[4]; + $auth_creds = $matches[2] . ':' . $matches[3]; + curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($this->curl, CURLOPT_USERPWD, $auth_creds); + } - if (!empty($http_proxy)) { - curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy); - if (!empty($http_proxy_port)) { - curl_setopt($this->curl, CURLOPT_PROXYPORT, $http_proxy_port); - } + curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt( + $this->curl, + CURLOPT_HTTPHEADER, + array( + 'Content-Type: application/json;charset=UTF-8', + 'Accept: application/json', + ) + ); + $this->setRequestTimeout(30000); + $this->setConnectionTimeout(30000); } - // Get credentials from $url (if any) - $matches = null; - if (preg_match("/^(https?:\/\/)(.*):(.*)@(.*?)/U", $url, $matches)) { - $this->url = $matches[1].$matches[4]; - $auth_creds = $matches[2].":".$matches[3]; - curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); - curl_setopt($this->curl, CURLOPT_USERPWD, $auth_creds); + /** + * Set timeout for the connect phase + * + * @param int $timeout_in_ms Timeout in milliseconds + * @return HttpCommandExecutor + */ + public function setConnectionTimeout($timeout_in_ms) + { + // There is a PHP bug in some versions which didn't define the constant. + curl_setopt( + $this->curl, + /* CURLOPT_CONNECTTIMEOUT_MS */ + 156, + $timeout_in_ms + ); + + return $this; } - curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); - curl_setopt( - $this->curl, - CURLOPT_HTTPHEADER, - array( - 'Content-Type: application/json;charset=UTF-8', - 'Accept: application/json', - ) - ); - $this->setRequestTimeout(30000); - $this->setConnectionTimeout(30000); - } + /** + * Set the maximum time of a request + * + * @param int $timeout_in_ms Timeout in milliseconds + * @return HttpCommandExecutor + */ + public function setRequestTimeout($timeout_in_ms) + { + // There is a PHP bug in some versions (at least for PHP 5.3.3) which + // didn't define the constant. + curl_setopt( + $this->curl, + /* CURLOPT_TIMEOUT_MS */ + 155, + $timeout_in_ms + ); - /** - * Set timeout for the connect phase - * - * @param int $timeout_in_ms Timeout in milliseconds - * @return HttpCommandExecutor - */ - public function setConnectionTimeout($timeout_in_ms) { - // There is a PHP bug in some versions which didn't define the constant. - curl_setopt( - $this->curl, - /* CURLOPT_CONNECTTIMEOUT_MS */ 156, - $timeout_in_ms - ); - return $this; - } + return $this; + } - /** - * Set the maximum time of a request - * - * @param int $timeout_in_ms Timeout in milliseconds - * @return HttpCommandExecutor - */ - public function setRequestTimeout($timeout_in_ms) { - // There is a PHP bug in some versions (at least for PHP 5.3.3) which - // didn't define the constant. - curl_setopt( - $this->curl, - /* CURLOPT_TIMEOUT_MS */ 155, - $timeout_in_ms - ); - return $this; - } + /** + * @param WebDriverCommand $command + * + * @throws WebDriverException + * @return mixed + */ + public function execute(WebDriverCommand $command) + { + if (!isset(self::$commands[$command->getName()])) { + throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); + } - /** - * @param WebDriverCommand $command - * - * @return mixed - * - * @throws WebDriverException - */ - public function execute(WebDriverCommand $command) { - if (!isset(self::$commands[$command->getName()])) { - throw new InvalidArgumentException( - $command->getName()." is not a valid command." - ); - } - $raw = self::$commands[$command->getName()]; - $http_method = $raw['method']; - $url = $raw['url']; - $url = str_replace(':sessionId', $command->getSessionID(), $url); - $params = $command->getParameters(); - foreach ($params as $name => $value) { - if ($name[0] === ':') { - $url = str_replace($name, $value, $url); - if ($http_method != 'POST') { - unset($params[$name]); + $raw = self::$commands[$command->getName()]; + $http_method = $raw['method']; + $url = $raw['url']; + $url = str_replace(':sessionId', $command->getSessionID(), $url); + $params = $command->getParameters(); + foreach ($params as $name => $value) { + if ($name[0] === ':') { + $url = str_replace($name, $value, $url); + if ($http_method != 'POST') { + unset($params[$name]); + } + } } - } - } - if ($params && is_array($params) && $http_method !== 'POST') { - throw new BadMethodCallException(sprintf( - 'The http method called for %s is %s but it has to be POST' . - ' if you want to pass the JSON params %s', - $url, - $http_method, - json_encode($params) - )); - } + if ($params && is_array($params) && $http_method !== 'POST') { + throw new BadMethodCallException(sprintf( + 'The http method called for %s is %s but it has to be POST' . + ' if you want to pass the JSON params %s', + $url, + $http_method, + json_encode($params) + )); + } - curl_setopt($this->curl, CURLOPT_URL, $this->url . $url); + curl_setopt($this->curl, CURLOPT_URL, $this->url . $url); - // https://github.com/facebook/php-webdriver/issues/173 - if ($command->getName() === DriverCommand::NEW_SESSION) { - curl_setopt($this->curl, CURLOPT_POST, 1); - } else { - curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method); - } + // https://github.com/facebook/php-webdriver/issues/173 + if ($command->getName() === DriverCommand::NEW_SESSION) { + curl_setopt($this->curl, CURLOPT_POST, 1); + } else { + curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method); + } - $encoded_params = null; + $encoded_params = null; - if ($http_method === 'POST' && $params && is_array($params)) { - $encoded_params = json_encode($params); - } + if ($http_method === 'POST' && $params && is_array($params)) { + $encoded_params = json_encode($params); + } - curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params); + curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params); - $raw_results = trim(curl_exec($this->curl)); + $raw_results = trim(curl_exec($this->curl)); - if ($error = curl_error($this->curl)) { - $msg = sprintf( - 'Curl error thrown for http %s to %s', - $http_method, - $url); - if ($params && is_array($params)) { - $msg .= sprintf(' with params: %s', json_encode($params)); - } - WebDriverException::throwException(-1, $msg . "\n\n" . $error, array()); - } + if ($error = curl_error($this->curl)) { + $msg = sprintf( + 'Curl error thrown for http %s to %s', + $http_method, + $url + ); + if ($params && is_array($params)) { + $msg .= sprintf(' with params: %s', json_encode($params)); + } + WebDriverException::throwException(-1, $msg . "\n\n" . $error, array()); + } - $results = json_decode($raw_results, true); + $results = json_decode($raw_results, true); - if ($results === null && json_last_error() !== JSON_ERROR_NONE) { - throw new WebDriverException( - sprintf( - "JSON decoding of remote response failed.\n". - "Error code: %d\n". - "The response: '%s'\n", - json_last_error(), - $raw_results - ) - ); - } + if ($results === null && json_last_error() !== JSON_ERROR_NONE) { + throw new WebDriverException( + sprintf( + "JSON decoding of remote response failed.\n" . + "Error code: %d\n" . + "The response: '%s'\n", + json_last_error(), + $raw_results + ) + ); + } - $value = null; - if (is_array($results) && array_key_exists('value', $results)) { - $value = $results['value']; - } + $value = null; + if (is_array($results) && array_key_exists('value', $results)) { + $value = $results['value']; + } - $message = null; - if (is_array($value) && array_key_exists('message', $value)) { - $message = $value['message']; - } + $message = null; + if (is_array($value) && array_key_exists('message', $value)) { + $message = $value['message']; + } - $sessionId = null; - if (is_array($results) && array_key_exists('sessionId', $results)) { - $sessionId = $results['sessionId']; - } + $sessionId = null; + if (is_array($results) && array_key_exists('sessionId', $results)) { + $sessionId = $results['sessionId']; + } + + $status = isset($results['status']) ? $results['status'] : 0; + WebDriverException::throwException($status, $message, $results); - $status = isset($results['status']) ? $results['status'] : 0; - WebDriverException::throwException($status, $message, $results); + $response = new WebDriverResponse($sessionId); - $response = new WebDriverResponse($sessionId); - return $response - ->setStatus($status) - ->setValue($value); - } + return $response + ->setStatus($status) + ->setValue($value); + } - /** - * @return string - */ - public function getAddressOfRemoteServer() { - return $this->url; - } + /** + * @return string + */ + public function getAddressOfRemoteServer() + { + return $this->url; + } } diff --git a/lib/Remote/LocalFileDetector.php b/lib/Remote/LocalFileDetector.php index 1308ed6a1..07f996cf0 100644 --- a/lib/Remote/LocalFileDetector.php +++ b/lib/Remote/LocalFileDetector.php @@ -15,16 +15,19 @@ namespace Facebook\WebDriver\Remote; -class LocalFileDetector implements FileDetector { +class LocalFileDetector implements FileDetector +{ /** * @param string $file * * @return null|string */ - public function getLocalFile($file) { - if (is_file($file)) { - return $file; + public function getLocalFile($file) + { + if (is_file($file)) { + return $file; + } + + return null; } - return null; - } } diff --git a/lib/Remote/RemoteExecuteMethod.php b/lib/Remote/RemoteExecuteMethod.php index e0ded1032..5a995215e 100644 --- a/lib/Remote/RemoteExecuteMethod.php +++ b/lib/Remote/RemoteExecuteMethod.php @@ -15,26 +15,25 @@ namespace Facebook\WebDriver\Remote; -class RemoteExecuteMethod implements ExecuteMethod { +class RemoteExecuteMethod implements ExecuteMethod +{ + private $driver; - private $driver; + /** + * @param RemoteWebDriver $driver + */ + public function __construct(RemoteWebDriver $driver) + { + $this->driver = $driver; + } - /** - * @param RemoteWebDriver $driver - */ - public function __construct(RemoteWebDriver $driver) { - $this->driver = $driver; - } - - /** - * @param string $command_name - * @param array $parameters - * @return mixed - */ - public function execute( - $command_name, - array $parameters = array() - ) { - return $this->driver->execute($command_name, $parameters); - } + /** + * @param string $command_name + * @param array $parameters + * @return mixed + */ + public function execute($command_name, array $parameters = array()) + { + return $this->driver->execute($command_name, $parameters); + } } diff --git a/lib/Remote/RemoteKeyboard.php b/lib/Remote/RemoteKeyboard.php index 2b297d1d9..7b2e114a2 100644 --- a/lib/Remote/RemoteKeyboard.php +++ b/lib/Remote/RemoteKeyboard.php @@ -15,63 +15,70 @@ namespace Facebook\WebDriver\Remote; -use Facebook\WebDriver\WebDriverKeys; use Facebook\WebDriver\WebDriverKeyboard; +use Facebook\WebDriver\WebDriverKeys; /** * Execute keyboard commands for RemoteWebDriver. */ -class RemoteKeyboard implements WebDriverKeyboard { +class RemoteKeyboard implements WebDriverKeyboard +{ + /** + * @var RemoteExecuteMethod + */ + private $executor; + + /** + * @param RemoteExecuteMethod $executor + */ + public function __construct(RemoteExecuteMethod $executor) + { + $this->executor = $executor; + } + + /** + * Send keys to active element + * @param string|array $keys + * @return $this + */ + public function sendKeys($keys) + { + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( + 'value' => WebDriverKeys::encode($keys), + )); - /** - * @var RemoteExecuteMethod - */ - private $executor; + return $this; + } - /** - * @param RemoteExecuteMethod $executor - */ - public function __construct(RemoteExecuteMethod $executor) { - $this->executor = $executor; - } + /** + * Press a modifier key + * + * @see WebDriverKeys + * @param string $key + * @return $this + */ + public function pressKey($key) + { + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( + 'value' => array((string) $key), + )); - /** - * Send keys to active element - * @param string|array $keys - * @return $this - */ - public function sendKeys($keys) { - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( - 'value' => WebDriverKeys::encode($keys), - )); - return $this; - } + return $this; + } - /** - * Press a modifier key - * - * @see WebDriverKeys - * @param string $key - * @return $this - */ - public function pressKey($key) { - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( - 'value' => array((string)$key), - )); - return $this; - } + /** + * Release a modifier key + * + * @see WebDriverKeys + * @param string $key + * @return $this + */ + public function releaseKey($key) + { + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( + 'value' => array((string) $key), + )); - /** - * Release a modifier key - * - * @see WebDriverKeys - * @param string $key - * @return $this - */ - public function releaseKey($key) { - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( - 'value' => array((string)$key), - )); - return $this; - } + return $this; + } } diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index c2e0d2263..00a4ef7b6 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -21,110 +21,124 @@ /** * Execute mouse commands for RemoteWebDriver. */ -class RemoteMouse implements WebDriverMouse { - - /** - * @var RemoteExecuteMethod - */ - private $executor; - - /** - * @param RemoteExecuteMethod $executor - */ - public function __construct(RemoteExecuteMethod $executor) { - $this->executor = $executor; - } - - /** - * @param null|WebDriverCoordinates $where - * - * @return RemoteMouse - */ - public function click(WebDriverCoordinates $where = null) { - $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::CLICK, array( - 'button' => 0, - )); - return $this; - } - - /** - * @param WebDriverCoordinates $where - * - * @return RemoteMouse - */ - public function contextClick(WebDriverCoordinates $where = null) { - $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::CLICK, array( - 'button' => 2, - )); - return $this; - } - - /** - * @param WebDriverCoordinates $where - * - * @return RemoteMouse - */ - public function doubleClick(WebDriverCoordinates $where = null) { - $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::DOUBLE_CLICK); - return $this; - } - - /** - * @param WebDriverCoordinates $where - * - * @return RemoteMouse - */ - public function mouseDown(WebDriverCoordinates $where = null) { - $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::MOUSE_DOWN); - return $this; - } - - /** - * @param WebDriverCoordinates $where - * @param int|null $x_offset - * @param int|null $y_offset - * - * @return RemoteMouse - */ - public function mouseMove(WebDriverCoordinates $where = null, - $x_offset = null, - $y_offset = null) { - $params = array(); - if ($where !== null) { - $params['element'] = $where->getAuxiliary(); +class RemoteMouse implements WebDriverMouse +{ + /** + * @var RemoteExecuteMethod + */ + private $executor; + + /** + * @param RemoteExecuteMethod $executor + */ + public function __construct(RemoteExecuteMethod $executor) + { + $this->executor = $executor; + } + + /** + * @param null|WebDriverCoordinates $where + * + * @return RemoteMouse + */ + public function click(WebDriverCoordinates $where = null) + { + $this->moveIfNeeded($where); + $this->executor->execute(DriverCommand::CLICK, array( + 'button' => 0, + )); + + return $this; + } + + /** + * @param WebDriverCoordinates $where + * + * @return RemoteMouse + */ + public function contextClick(WebDriverCoordinates $where = null) + { + $this->moveIfNeeded($where); + $this->executor->execute(DriverCommand::CLICK, array( + 'button' => 2, + )); + + return $this; + } + + /** + * @param WebDriverCoordinates $where + * + * @return RemoteMouse + */ + public function doubleClick(WebDriverCoordinates $where = null) + { + $this->moveIfNeeded($where); + $this->executor->execute(DriverCommand::DOUBLE_CLICK); + + return $this; } - if ($x_offset !== null) { - $params['xoffset'] = $x_offset; + + /** + * @param WebDriverCoordinates $where + * + * @return RemoteMouse + */ + public function mouseDown(WebDriverCoordinates $where = null) + { + $this->moveIfNeeded($where); + $this->executor->execute(DriverCommand::MOUSE_DOWN); + + return $this; } - if ($y_offset !== null) { - $params['yoffset'] = $y_offset; + + /** + * @param WebDriverCoordinates $where + * @param int|null $x_offset + * @param int|null $y_offset + * + * @return RemoteMouse + */ + public function mouseMove( + WebDriverCoordinates $where = null, + $x_offset = null, + $y_offset = null + ) { + $params = array(); + if ($where !== null) { + $params['element'] = $where->getAuxiliary(); + } + if ($x_offset !== null) { + $params['xoffset'] = $x_offset; + } + if ($y_offset !== null) { + $params['yoffset'] = $y_offset; + } + $this->executor->execute(DriverCommand::MOVE_TO, $params); + + return $this; } - $this->executor->execute(DriverCommand::MOVE_TO, $params); - return $this; - } - - /** - * @param WebDriverCoordinates $where - * - * @return RemoteMouse - */ - public function mouseUp(WebDriverCoordinates $where = null) { - $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::MOUSE_UP); - return $this; - } - - /** - * @param WebDriverCoordinates $where - * @return void - */ - protected function moveIfNeeded(WebDriverCoordinates $where = null) { - if ($where) { - $this->mouseMove($where); + + /** + * @param WebDriverCoordinates $where + * + * @return RemoteMouse + */ + public function mouseUp(WebDriverCoordinates $where = null) + { + $this->moveIfNeeded($where); + $this->executor->execute(DriverCommand::MOUSE_UP); + + return $this; + } + + /** + * @param WebDriverCoordinates $where + */ + protected function moveIfNeeded(WebDriverCoordinates $where = null) + { + if ($where) { + $this->mouseMove($where); + } } - } } diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index e2f5a0aea..67d2ad7cd 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -15,90 +15,97 @@ namespace Facebook\WebDriver\Remote; -use Facebook\WebDriver\WebDriverTargetLocator; -use Facebook\WebDriver\WebDriverElement; -use Facebook\WebDriver\WebDriverAlert; use Facebook\WebDriver\WebDriver; +use Facebook\WebDriver\WebDriverAlert; +use Facebook\WebDriver\WebDriverElement; +use Facebook\WebDriver\WebDriverTargetLocator; /** * Used to locate a given frame or window for RemoteWebDriver. */ -class RemoteTargetLocator implements WebDriverTargetLocator { +class RemoteTargetLocator implements WebDriverTargetLocator +{ + protected $executor; + protected $driver; - protected $executor; - protected $driver; + public function __construct($executor, $driver) + { + $this->executor = $executor; + $this->driver = $driver; + } - public function __construct($executor, $driver) { - $this->executor = $executor; - $this->driver = $driver; - } + /** + * Switch to the main document if the page contains iframes. Otherwise, switch + * to the first frame on the page. + * + * @return WebDriver The driver focused on the top window or the first frame. + */ + public function defaultContent() + { + $params = array('id' => null); + $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params); - /** - * Switch to the main document if the page contains iframes. Otherwise, switch - * to the first frame on the page. - * - * @return WebDriver The driver focused on the top window or the first frame. - */ - public function defaultContent() { - $params = array('id' => null); - $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params); + return $this->driver; + } - return $this->driver; - } + /** + * Switch to the iframe by its id or name. + * + * @param WebDriverElement|string $frame The WebDriverElement, + * the id or the name of the frame. + * @return WebDriver The driver focused on the given frame. + */ + public function frame($frame) + { + if ($frame instanceof WebDriverElement) { + $id = array('ELEMENT' => $frame->getID()); + } else { + $id = (string) $frame; + } - /** - * Switch to the iframe by its id or name. - * - * @param WebDriverElement|string $frame The WebDriverElement, - the id or the name of the frame. - * @return WebDriver The driver focused on the given frame. - */ - public function frame($frame) { - if ($frame instanceof WebDriverElement) { - $id = array('ELEMENT' => $frame->getID()); - } else { - $id = (string)$frame; - } + $params = array('id' => $id); + $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params); - $params = array('id' => $id); - $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params); + return $this->driver; + } - return $this->driver; - } + /** + * Switch the focus to another window by its handle. + * + * @param string $handle The handle of the window to be focused on. + * @return WebDriver Tge driver focused on the given window. + * @see WebDriver::getWindowHandles + */ + public function window($handle) + { + $params = array('name' => (string) $handle); + $this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params); - /** - * Switch the focus to another window by its handle. - * - * @param string $handle The handle of the window to be focused on. - * @return WebDriver Tge driver focused on the given window. - * @see WebDriver::getWindowHandles - */ - public function window($handle) { - $params = array('name' => (string)$handle); - $this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params); + return $this->driver; + } - return $this->driver; - } + /** + * Switch to the currently active modal dialog for this particular driver + * instance. + * + * @return WebDriverAlert + */ + public function alert() + { + return new WebDriverAlert($this->executor); + } - /** - * Switch to the currently active modal dialog for this particular driver - * instance. - * - * @return WebDriverAlert - */ - public function alert() { - return new WebDriverAlert($this->executor); - } + /** + * Switches to the element that currently has focus within the document + * currently "switched to", or the body element if this cannot be detected. + * + * @return RemoteWebElement + */ + public function activeElement() + { + $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT); + $method = new RemoteExecuteMethod($this->driver); - /** - * Switches to the element that currently has focus within the document - * currently "switched to", or the body element if this cannot be detected. - * - * @return RemoteWebElement - */ - public function activeElement() { - $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT); - $method = new RemoteExecuteMethod($this->driver); - return new RemoteWebElement($method, $response['ELEMENT']); - } + return new RemoteWebElement($method, $response['ELEMENT']); + } } diff --git a/lib/Remote/RemoteTouchScreen.php b/lib/Remote/RemoteTouchScreen.php index 7929d5db3..a052a6063 100644 --- a/lib/Remote/RemoteTouchScreen.php +++ b/lib/Remote/RemoteTouchScreen.php @@ -21,177 +21,181 @@ /** * Execute touch commands for RemoteWebDriver. */ -class RemoteTouchScreen implements WebDriverTouchScreen { - - /** - * @var RemoteExecuteMethod - */ - private $executor; - - /** - * @param RemoteExecuteMethod $executor - */ - public function __construct(RemoteExecuteMethod $executor) { - $this->executor = $executor; - } - - /** - * @param WebDriverElement $element - * - * @return RemoteTouchScreen The instance. - */ - public function tap(WebDriverElement $element) { - $this->executor->execute( - DriverCommand::TOUCH_SINGLE_TAP, - array('element' => $element->getID()) - ); - - return $this; - } - - /** - * @param WebDriverElement $element - * - * @return RemoteTouchScreen The instance. - */ - public function doubleTap(WebDriverElement $element) { - $this->executor->execute( - DriverCommand::TOUCH_DOUBLE_TAP, - array('element' => $element->getID()) - ); - - return $this; - } - - /** - * @param int $x - * @param int $y - * - * @return RemoteTouchScreen The instance. - */ - public function down($x, $y) { - $this->executor->execute(DriverCommand::TOUCH_DOWN, array( - 'x' => $x, - 'y' => $y, - )); - - return $this; - } - - - /** - * @param int $xspeed - * @param int $yspeed - * - * @return RemoteTouchScreen The instance. - */ - public function flick($xspeed, $yspeed) { - $this->executor->execute(DriverCommand::TOUCH_FLICK, array( - 'xspeed' => $xspeed, - 'yspeed' => $yspeed, - )); - - return $this; - } - - /** - * @param WebDriverElement $element - * @param int $xoffset - * @param int $yoffset - * @param int $speed - * - * @return RemoteTouchScreen The instance. - */ - public function flickFromElement( - WebDriverElement $element, $xoffset, $yoffset, $speed - ) { - $this->executor->execute(DriverCommand::TOUCH_FLICK, array( - 'xoffset' => $xoffset, - 'yoffset' => $yoffset, - 'element' => $element->getID(), - 'speed' => $speed, - )); - - return $this; - } - - /** - * @param WebDriverElement $element - * - * @return RemoteTouchScreen The instance. - */ - public function longPress(WebDriverElement $element) { - $this->executor->execute( - DriverCommand::TOUCH_LONG_PRESS, - array('element' => $element->getID()) - ); - - return $this; - } - - /** - * @param int $x - * @param int $y - * - * @return RemoteTouchScreen The instance. - */ - public function move($x, $y) { - $this->executor->execute(DriverCommand::TOUCH_MOVE, array( - 'x' => $x, - 'y' => $y, - )); - - return $this; - } - - /** - * @param int $xoffset - * @param int $yoffset - * - * @return RemoteTouchScreen The instance. - */ - public function scroll($xoffset, $yoffset) { - $this->executor->execute(DriverCommand::TOUCH_SCROLL, array( - 'xoffset' => $xoffset, - 'yoffset' => $yoffset, - )); - - return $this; - } - - /** - * @param WebDriverElement $element - * @param int $xoffset - * @param int $yoffset - * - * @return RemoteTouchScreen The instance. - */ - public function scrollFromElement( - WebDriverElement $element, $xoffset, $yoffset - ) { - $this->executor->execute(DriverCommand::TOUCH_SCROLL, array( - 'element' => $element->getID(), - 'xoffset' => $xoffset, - 'yoffset' => $yoffset, - )); - - return $this; - } - - - /** - * @param int $x - * @param int $y - * - * @return RemoteTouchScreen The instance. - */ - public function up($x, $y) { - $this->executor->execute(DriverCommand::TOUCH_UP, array( - 'x' => $x, - 'y' => $y, - )); - - return $this; - } - +class RemoteTouchScreen implements WebDriverTouchScreen +{ + /** + * @var RemoteExecuteMethod + */ + private $executor; + + /** + * @param RemoteExecuteMethod $executor + */ + public function __construct(RemoteExecuteMethod $executor) + { + $this->executor = $executor; + } + + /** + * @param WebDriverElement $element + * + * @return RemoteTouchScreen The instance. + */ + public function tap(WebDriverElement $element) + { + $this->executor->execute( + DriverCommand::TOUCH_SINGLE_TAP, + array('element' => $element->getID()) + ); + + return $this; + } + + /** + * @param WebDriverElement $element + * + * @return RemoteTouchScreen The instance. + */ + public function doubleTap(WebDriverElement $element) + { + $this->executor->execute( + DriverCommand::TOUCH_DOUBLE_TAP, + array('element' => $element->getID()) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * + * @return RemoteTouchScreen The instance. + */ + public function down($x, $y) + { + $this->executor->execute(DriverCommand::TOUCH_DOWN, array( + 'x' => $x, + 'y' => $y, + )); + + return $this; + } + + /** + * @param int $xspeed + * @param int $yspeed + * + * @return RemoteTouchScreen The instance. + */ + public function flick($xspeed, $yspeed) + { + $this->executor->execute(DriverCommand::TOUCH_FLICK, array( + 'xspeed' => $xspeed, + 'yspeed' => $yspeed, + )); + + return $this; + } + + /** + * @param WebDriverElement $element + * @param int $xoffset + * @param int $yoffset + * @param int $speed + * + * @return RemoteTouchScreen The instance. + */ + public function flickFromElement(WebDriverElement $element, $xoffset, $yoffset, $speed) + { + $this->executor->execute(DriverCommand::TOUCH_FLICK, array( + 'xoffset' => $xoffset, + 'yoffset' => $yoffset, + 'element' => $element->getID(), + 'speed' => $speed, + )); + + return $this; + } + + /** + * @param WebDriverElement $element + * + * @return RemoteTouchScreen The instance. + */ + public function longPress(WebDriverElement $element) + { + $this->executor->execute( + DriverCommand::TOUCH_LONG_PRESS, + array('element' => $element->getID()) + ); + + return $this; + } + + /** + * @param int $x + * @param int $y + * + * @return RemoteTouchScreen The instance. + */ + public function move($x, $y) + { + $this->executor->execute(DriverCommand::TOUCH_MOVE, array( + 'x' => $x, + 'y' => $y, + )); + + return $this; + } + + /** + * @param int $xoffset + * @param int $yoffset + * + * @return RemoteTouchScreen The instance. + */ + public function scroll($xoffset, $yoffset) + { + $this->executor->execute(DriverCommand::TOUCH_SCROLL, array( + 'xoffset' => $xoffset, + 'yoffset' => $yoffset, + )); + + return $this; + } + + /** + * @param WebDriverElement $element + * @param int $xoffset + * @param int $yoffset + * + * @return RemoteTouchScreen The instance. + */ + public function scrollFromElement(WebDriverElement $element, $xoffset, $yoffset) + { + $this->executor->execute(DriverCommand::TOUCH_SCROLL, array( + 'element' => $element->getID(), + 'xoffset' => $xoffset, + 'yoffset' => $yoffset, + )); + + return $this; + } + + /** + * @param int $x + * @param int $y + * + * @return RemoteTouchScreen The instance. + */ + public function up($x, $y) + { + $this->executor->execute(DriverCommand::TOUCH_UP, array( + 'x' => $x, + 'y' => $y, + )); + + return $this; + } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 8fb7003c1..4f885bc43 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -25,155 +25,162 @@ use Facebook\WebDriver\WebDriverOptions; use Facebook\WebDriver\WebDriverWait; -class RemoteWebDriver implements WebDriver, JavaScriptExecutor { - /** - * @var HttpCommandExecutor - */ - protected $executor; - /** - * @var string - */ - protected $sessionID; - /** - * @var RemoteMouse - */ - protected $mouse; - /** - * @var RemoteKeyboard - */ - protected $keyboard; - /** - * @var RemoteTouchScreen - */ - protected $touch; - /** - * @var RemoteExecuteMethod - */ - protected $executeMethod; - - protected function __construct() {} - - /** - * Construct the RemoteWebDriver by a desired capabilities. - * - * @param string $url The url of the remote server - * @param DesiredCapabilities|array $desired_capabilities The desired capabilities - * @param int|null $connection_timeout_in_ms - * @param int|null $request_timeout_in_ms - * @param string|null $http_proxy The proxy to tunnel requests through - * @param int|null $http_proxy_port - * @return RemoteWebDriver - */ - public static function create( - $url = 'http://localhost:4444/wd/hub', - $desired_capabilities = null, - $connection_timeout_in_ms = null, - $request_timeout_in_ms = null, - $http_proxy = null, - $http_proxy_port = null - ) { - $url = preg_replace('#/+$#', '', $url); - - // Passing DesiredCapabilities as $desired_capabilities is encouraged but - // array is also accepted for legacy reason. - if ($desired_capabilities instanceof DesiredCapabilities) { - $desired_capabilities = $desired_capabilities->toArray(); - } - - $executor = new HttpCommandExecutor($url, $http_proxy, $http_proxy_port); - if ($connection_timeout_in_ms !== null) { - $executor->setConnectionTimeout($connection_timeout_in_ms); - } - if ($request_timeout_in_ms !== null) { - $executor->setRequestTimeout($request_timeout_in_ms); - } - - $command = new WebDriverCommand( - null, - DriverCommand::NEW_SESSION, - array('desiredCapabilities' => $desired_capabilities) - ); - - $response = $executor->execute($command); - - $driver = new static(); - $driver->setSessionID($response->getSessionID()) - ->setCommandExecutor($executor); - return $driver; - } - - /** - * [Experimental] Construct the RemoteWebDriver by an existing session. - * - * This constructor can boost the performance a lot by reusing the same - * browser for the whole test suite. You do not have to pass the desired - * capabilities because the session was created before. - * - * @param string $url The url of the remote server - * @param string $session_id The existing session id - * @return RemoteWebDriver - */ - public static function createBySessionID( - $session_id, - $url = 'http://localhost:4444/wd/hub' - ) { - $driver = new static(); - $driver->setSessionID($session_id) - ->setCommandExecutor(new HttpCommandExecutor($url)); - return $driver; - } - - /** - * Close the current window. - * - * @return RemoteWebDriver The current instance. - */ - public function close() { - $this->execute(DriverCommand::CLOSE, array()); - - return $this; - } - - /** - * Find the first WebDriverElement using the given mechanism. - * - * @param WebDriverBy $by - * @return RemoteWebElement NoSuchElementException is thrown in - * HttpCommandExecutor if no element is found. - * @see WebDriverBy - */ - public function findElement(WebDriverBy $by) { - $params = array('using' => $by->getMechanism(), 'value' => $by->getValue()); - $raw_element = $this->execute( - DriverCommand::FIND_ELEMENT, - $params - ); - - return $this->newElement($raw_element['ELEMENT']); - } - - /** - * Find all WebDriverElements within the current page using the given - * mechanism. - * - * @param WebDriverBy $by - * @return RemoteWebElement[] A list of all WebDriverElements, or an empty - * array if nothing matches - * @see WebDriverBy - */ - public function findElements(WebDriverBy $by) { - $params = array('using' => $by->getMechanism(), 'value' => $by->getValue()); - $raw_elements = $this->execute( - DriverCommand::FIND_ELEMENTS, - $params - ); - - $elements = array(); - foreach ($raw_elements as $raw_element) { - $elements[] = $this->newElement($raw_element['ELEMENT']); - } - return $elements; - } +class RemoteWebDriver implements WebDriver, JavaScriptExecutor +{ + /** + * @var HttpCommandExecutor + */ + protected $executor; + /** + * @var string + */ + protected $sessionID; + /** + * @var RemoteMouse + */ + protected $mouse; + /** + * @var RemoteKeyboard + */ + protected $keyboard; + /** + * @var RemoteTouchScreen + */ + protected $touch; + /** + * @var RemoteExecuteMethod + */ + protected $executeMethod; + + protected function __construct() + { + } + + /** + * Construct the RemoteWebDriver by a desired capabilities. + * + * @param string $url The url of the remote server + * @param DesiredCapabilities|array $desired_capabilities The desired capabilities + * @param int|null $connection_timeout_in_ms + * @param int|null $request_timeout_in_ms + * @param string|null $http_proxy The proxy to tunnel requests through + * @param int|null $http_proxy_port + * @return RemoteWebDriver + */ + public static function create( + $url = 'http://localhost:4444/wd/hub', + $desired_capabilities = null, + $connection_timeout_in_ms = null, + $request_timeout_in_ms = null, + $http_proxy = null, + $http_proxy_port = null + ) { + $url = preg_replace('#/+$#', '', $url); + + // Passing DesiredCapabilities as $desired_capabilities is encouraged but + // array is also accepted for legacy reason. + if ($desired_capabilities instanceof DesiredCapabilities) { + $desired_capabilities = $desired_capabilities->toArray(); + } + + $executor = new HttpCommandExecutor($url, $http_proxy, $http_proxy_port); + if ($connection_timeout_in_ms !== null) { + $executor->setConnectionTimeout($connection_timeout_in_ms); + } + if ($request_timeout_in_ms !== null) { + $executor->setRequestTimeout($request_timeout_in_ms); + } + + $command = new WebDriverCommand( + null, + DriverCommand::NEW_SESSION, + array('desiredCapabilities' => $desired_capabilities) + ); + + $response = $executor->execute($command); + + $driver = new static(); + $driver->setSessionID($response->getSessionID()) + ->setCommandExecutor($executor); + + return $driver; + } + + /** + * [Experimental] Construct the RemoteWebDriver by an existing session. + * + * This constructor can boost the performance a lot by reusing the same + * browser for the whole test suite. You do not have to pass the desired + * capabilities because the session was created before. + * + * @param string $url The url of the remote server + * @param string $session_id The existing session id + * @return RemoteWebDriver + */ + public static function createBySessionID($session_id, $url = 'http://localhost:4444/wd/hub') + { + $driver = new static(); + $driver->setSessionID($session_id) + ->setCommandExecutor(new HttpCommandExecutor($url)); + + return $driver; + } + + /** + * Close the current window. + * + * @return RemoteWebDriver The current instance. + */ + public function close() + { + $this->execute(DriverCommand::CLOSE, array()); + + return $this; + } + + /** + * Find the first WebDriverElement using the given mechanism. + * + * @param WebDriverBy $by + * @return RemoteWebElement NoSuchElementException is thrown in + * HttpCommandExecutor if no element is found. + * @see WebDriverBy + */ + public function findElement(WebDriverBy $by) + { + $params = array('using' => $by->getMechanism(), 'value' => $by->getValue()); + $raw_element = $this->execute( + DriverCommand::FIND_ELEMENT, + $params + ); + + return $this->newElement($raw_element['ELEMENT']); + } + + /** + * Find all WebDriverElements within the current page using the given + * mechanism. + * + * @param WebDriverBy $by + * @return RemoteWebElement[] A list of all WebDriverElements, or an empty + * array if nothing matches + * @see WebDriverBy + */ + public function findElements(WebDriverBy $by) + { + $params = array('using' => $by->getMechanism(), 'value' => $by->getValue()); + $raw_elements = $this->execute( + DriverCommand::FIND_ELEMENTS, + $params + ); + + $elements = array(); + foreach ($raw_elements as $raw_element) { + $elements[] = $this->newElement($raw_element['ELEMENT']); + } + + return $elements; + } /** * Load a new web page in the current browser window. @@ -182,333 +189,366 @@ public function findElements(WebDriverBy $by) { * * @return RemoteWebDriver The current instance. */ - public function get($url) { - $params = array('url' => (string)$url); - $this->execute(DriverCommand::GET, $params); - - return $this; - } - - /** - * Get a string representing the current URL that the browser is looking at. - * - * @return string The current URL. - */ - public function getCurrentURL() { - return $this->execute(DriverCommand::GET_CURRENT_URL); - } - - /** - * Get the source of the last loaded page. - * - * @return string The current page source. - */ - public function getPageSource() { - return $this->execute(DriverCommand::GET_PAGE_SOURCE); - } - - /** - * Get the title of the current page. - * - * @return string The title of the current page. - */ - public function getTitle() { - return $this->execute(DriverCommand::GET_TITLE); - } - - /** - * Return an opaque handle to this window that uniquely identifies it within - * this driver instance. - * - * @return string The current window handle. - */ - public function getWindowHandle() { - return $this->execute( - DriverCommand::GET_CURRENT_WINDOW_HANDLE, - array() - ); - } - - /** - * Get all window handles available to the current session. - * - * @return array An array of string containing all available window handles. - */ - public function getWindowHandles() { - return $this->execute(DriverCommand::GET_WINDOW_HANDLES, array()); - } - - /** - * Quits this driver, closing every associated window. - * - * @return void - */ - public function quit() { - $this->execute(DriverCommand::QUIT); - $this->executor = null; - } - - /** - * Prepare arguments for JavaScript injection - * - * @param array $arguments - * @return array - */ - private function prepareScriptArguments(array $arguments) { - $args = array(); - foreach ($arguments as $key => $value) { - if ($value instanceof WebDriverElement) { - $args[$key] = array('ELEMENT'=>$value->getID()); - } else { - if (is_array($value)) { - $value = $this->prepareScriptArguments($value); + public function get($url) + { + $params = array('url' => (string) $url); + $this->execute(DriverCommand::GET, $params); + + return $this; + } + + /** + * Get a string representing the current URL that the browser is looking at. + * + * @return string The current URL. + */ + public function getCurrentURL() + { + return $this->execute(DriverCommand::GET_CURRENT_URL); + } + + /** + * Get the source of the last loaded page. + * + * @return string The current page source. + */ + public function getPageSource() + { + return $this->execute(DriverCommand::GET_PAGE_SOURCE); + } + + /** + * Get the title of the current page. + * + * @return string The title of the current page. + */ + public function getTitle() + { + return $this->execute(DriverCommand::GET_TITLE); + } + + /** + * Return an opaque handle to this window that uniquely identifies it within + * this driver instance. + * + * @return string The current window handle. + */ + public function getWindowHandle() + { + return $this->execute( + DriverCommand::GET_CURRENT_WINDOW_HANDLE, + array() + ); + } + + /** + * Get all window handles available to the current session. + * + * @return array An array of string containing all available window handles. + */ + public function getWindowHandles() + { + return $this->execute(DriverCommand::GET_WINDOW_HANDLES, array()); + } + + /** + * Quits this driver, closing every associated window. + */ + public function quit() + { + $this->execute(DriverCommand::QUIT); + $this->executor = null; + } + + /** + * Prepare arguments for JavaScript injection + * + * @param array $arguments + * @return array + */ + private function prepareScriptArguments(array $arguments) + { + $args = array(); + foreach ($arguments as $key => $value) { + if ($value instanceof WebDriverElement) { + $args[$key] = array('ELEMENT' => $value->getID()); + } else { + if (is_array($value)) { + $value = $this->prepareScriptArguments($value); + } + $args[$key] = $value; + } } - $args[$key] = $value; - } - } - return $args; - } - - /** - * Inject a snippet of JavaScript into the page for execution in the context - * of the currently selected frame. The executed script is assumed to be - * synchronous and the result of evaluating the script will be returned. - * - * @param string $script The script to inject. - * @param array $arguments The arguments of the script. - * @return mixed The return value of the script. - */ - public function executeScript($script, array $arguments = array()) { - $params = array( - 'script' => $script, - 'args' => $this->prepareScriptArguments($arguments), - ); - return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params); - } - - /** - * Inject a snippet of JavaScript into the page for asynchronous execution in - * the context of the currently selected frame. - * - * The driver will pass a callback as the last argument to the snippet, and - * block until the callback is invoked. - * - * @see WebDriverExecuteAsyncScriptTestCase - * - * @param string $script The script to inject. - * @param array $arguments The arguments of the script. - * @return mixed The value passed by the script to the callback. - */ - public function executeAsyncScript($script, array $arguments = array()) { - $params = array( - 'script' => $script, - 'args' => $this->prepareScriptArguments($arguments), - ); - return $this->execute( - DriverCommand::EXECUTE_ASYNC_SCRIPT, - $params - ); - } - - /** - * Take a screenshot of the current page. - * - * @param string $save_as The path of the screenshot to be saved. - * @return string The screenshot in PNG format. - */ - public function takeScreenshot($save_as = null) { - $screenshot = base64_decode( - $this->execute(DriverCommand::SCREENSHOT) - ); - if ($save_as) { - file_put_contents($save_as, $screenshot); - } - return $screenshot; - } - - /** - * Construct a new WebDriverWait by the current WebDriver instance. - * Sample usage: - * - * $driver->wait(20, 1000)->until( - * WebDriverExpectedCondition::titleIs('WebDriver Page') - * ); - * - * @param int $timeout_in_second - * @param int $interval_in_millisecond - * - * @return WebDriverWait - */ - public function wait( - $timeout_in_second = 30, - $interval_in_millisecond = 250) { - return new WebDriverWait( - $this, $timeout_in_second, $interval_in_millisecond - ); - } - - /** - * An abstraction for managing stuff you would do in a browser menu. For - * example, adding and deleting cookies. - * - * @return WebDriverOptions - */ - public function manage() { - return new WebDriverOptions($this->getExecuteMethod()); - } - - /** - * An abstraction allowing the driver to access the browser's history and to - * navigate to a given URL. - * - * @return WebDriverNavigation - * @see WebDriverNavigation - */ - public function navigate() { - return new WebDriverNavigation($this->getExecuteMethod()); - } - - /** - * Switch to a different window or frame. - * - * @return RemoteTargetLocator - * @see RemoteTargetLocator - */ - public function switchTo() { - return new RemoteTargetLocator($this->getExecuteMethod(), $this); - } - - /** - * @return RemoteMouse - */ - public function getMouse() { - if (!$this->mouse) { - $this->mouse = new RemoteMouse($this->getExecuteMethod()); - } - return $this->mouse; - } - - /** - * @return RemoteKeyboard - */ - public function getKeyboard() { - if (!$this->keyboard) { - $this->keyboard = new RemoteKeyboard($this->getExecuteMethod()); - } - return $this->keyboard; - } - - /** - * @return RemoteTouchScreen - */ - public function getTouch() { - if (!$this->touch) { - $this->touch = new RemoteTouchScreen($this->getExecuteMethod()); - } - return $this->touch; - } - - protected function getExecuteMethod() { - if (!$this->executeMethod) { - $this->executeMethod = new RemoteExecuteMethod($this); - } - return $this->executeMethod; - } - - /** - * Construct a new action builder. - * - * @return WebDriverActions - */ - public function action() { - return new WebDriverActions($this); - } - - /** - * Return the WebDriverElement with the given id. - * - * @param string $id The id of the element to be created. - * @return RemoteWebElement - */ - protected function newElement($id) { - return new RemoteWebElement($this->getExecuteMethod(), $id); - } - - /** - * Set the command executor of this RemoteWebdriver - * - * @param WebDriverCommandExecutor $executor - * @return RemoteWebDriver - */ - public function setCommandExecutor(WebDriverCommandExecutor $executor) { - $this->executor = $executor; - return $this; - } - - /** - * Set the command executor of this RemoteWebdriver - * - * @return HttpCommandExecutor - */ - public function getCommandExecutor() { - return $this->executor; - } - - /** - * Set the session id of the RemoteWebDriver. - * - * @param string $session_id - * @return RemoteWebDriver - */ - public function setSessionID($session_id) { - $this->sessionID = $session_id; - return $this; - } - - /** - * Get current selenium sessionID - * - * @return string sessionID - */ - public function getSessionID() { - return $this->sessionID; - } - - /** - * Get all selenium sessions. - * - * @param string $url The url of the remote server - * @param int $timeout_in_ms - * @return array - */ - public static function getAllSessions( - $url = 'http://localhost:4444/wd/hub', - $timeout_in_ms = 30000 - ) { - $executor = new HttpCommandExecutor($url); - $executor->setConnectionTimeout($timeout_in_ms); - - $command = new WebDriverCommand( - null, - DriverCommand::GET_ALL_SESSIONS, - array() - ); - - return $executor->execute($command)->getValue(); - } - - public function execute($command_name, $params = array()) { - $command = new WebDriverCommand( - $this->sessionID, - $command_name, - $params - ); - - if ($this->executor) { - $response = $this->executor->execute($command); - return $response->getValue(); - } else { - return null; - } - } + + return $args; + } + + /** + * Inject a snippet of JavaScript into the page for execution in the context + * of the currently selected frame. The executed script is assumed to be + * synchronous and the result of evaluating the script will be returned. + * + * @param string $script The script to inject. + * @param array $arguments The arguments of the script. + * @return mixed The return value of the script. + */ + public function executeScript($script, array $arguments = array()) + { + $params = array( + 'script' => $script, + 'args' => $this->prepareScriptArguments($arguments), + ); + + return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params); + } + + /** + * Inject a snippet of JavaScript into the page for asynchronous execution in + * the context of the currently selected frame. + * + * The driver will pass a callback as the last argument to the snippet, and + * block until the callback is invoked. + * + * @see WebDriverExecuteAsyncScriptTestCase + * + * @param string $script The script to inject. + * @param array $arguments The arguments of the script. + * @return mixed The value passed by the script to the callback. + */ + public function executeAsyncScript($script, array $arguments = array()) + { + $params = array( + 'script' => $script, + 'args' => $this->prepareScriptArguments($arguments), + ); + + return $this->execute( + DriverCommand::EXECUTE_ASYNC_SCRIPT, + $params + ); + } + + /** + * Take a screenshot of the current page. + * + * @param string $save_as The path of the screenshot to be saved. + * @return string The screenshot in PNG format. + */ + public function takeScreenshot($save_as = null) + { + $screenshot = base64_decode( + $this->execute(DriverCommand::SCREENSHOT) + ); + if ($save_as) { + file_put_contents($save_as, $screenshot); + } + + return $screenshot; + } + + /** + * Construct a new WebDriverWait by the current WebDriver instance. + * Sample usage: + * + * $driver->wait(20, 1000)->until( + * WebDriverExpectedCondition::titleIs('WebDriver Page') + * ); + * + * @param int $timeout_in_second + * @param int $interval_in_millisecond + * + * @return WebDriverWait + */ + public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) + { + return new WebDriverWait( + $this, + $timeout_in_second, + $interval_in_millisecond + ); + } + + /** + * An abstraction for managing stuff you would do in a browser menu. For + * example, adding and deleting cookies. + * + * @return WebDriverOptions + */ + public function manage() + { + return new WebDriverOptions($this->getExecuteMethod()); + } + + /** + * An abstraction allowing the driver to access the browser's history and to + * navigate to a given URL. + * + * @return WebDriverNavigation + * @see WebDriverNavigation + */ + public function navigate() + { + return new WebDriverNavigation($this->getExecuteMethod()); + } + + /** + * Switch to a different window or frame. + * + * @return RemoteTargetLocator + * @see RemoteTargetLocator + */ + public function switchTo() + { + return new RemoteTargetLocator($this->getExecuteMethod(), $this); + } + + /** + * @return RemoteMouse + */ + public function getMouse() + { + if (!$this->mouse) { + $this->mouse = new RemoteMouse($this->getExecuteMethod()); + } + + return $this->mouse; + } + + /** + * @return RemoteKeyboard + */ + public function getKeyboard() + { + if (!$this->keyboard) { + $this->keyboard = new RemoteKeyboard($this->getExecuteMethod()); + } + + return $this->keyboard; + } + + /** + * @return RemoteTouchScreen + */ + public function getTouch() + { + if (!$this->touch) { + $this->touch = new RemoteTouchScreen($this->getExecuteMethod()); + } + + return $this->touch; + } + + protected function getExecuteMethod() + { + if (!$this->executeMethod) { + $this->executeMethod = new RemoteExecuteMethod($this); + } + + return $this->executeMethod; + } + + /** + * Construct a new action builder. + * + * @return WebDriverActions + */ + public function action() + { + return new WebDriverActions($this); + } + + /** + * Return the WebDriverElement with the given id. + * + * @param string $id The id of the element to be created. + * @return RemoteWebElement + */ + protected function newElement($id) + { + return new RemoteWebElement($this->getExecuteMethod(), $id); + } + + /** + * Set the command executor of this RemoteWebdriver + * + * @param WebDriverCommandExecutor $executor + * @return RemoteWebDriver + */ + public function setCommandExecutor(WebDriverCommandExecutor $executor) + { + $this->executor = $executor; + + return $this; + } + + /** + * Set the command executor of this RemoteWebdriver + * + * @return HttpCommandExecutor + */ + public function getCommandExecutor() + { + return $this->executor; + } + + /** + * Set the session id of the RemoteWebDriver. + * + * @param string $session_id + * @return RemoteWebDriver + */ + public function setSessionID($session_id) + { + $this->sessionID = $session_id; + + return $this; + } + + /** + * Get current selenium sessionID + * + * @return string sessionID + */ + public function getSessionID() + { + return $this->sessionID; + } + + /** + * Get all selenium sessions. + * + * @param string $url The url of the remote server + * @param int $timeout_in_ms + * @return array + */ + public static function getAllSessions($url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000) + { + $executor = new HttpCommandExecutor($url); + $executor->setConnectionTimeout($timeout_in_ms); + + $command = new WebDriverCommand( + null, + DriverCommand::GET_ALL_SESSIONS, + array() + ); + + return $executor->execute($command)->getValue(); + } + + public function execute($command_name, $params = array()) + { + $command = new WebDriverCommand( + $this->sessionID, + $command_name, + $params + ); + + if ($this->executor) { + $response = $this->executor->execute($command); + + return $response->getValue(); + } else { + return null; + } + } } diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index e9e1ca31e..217356592 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -28,395 +28,429 @@ /** * Represents an HTML element. */ -class RemoteWebElement implements WebDriverElement, WebDriverLocatable { - - /** - * @var RemoteExecuteMethod - */ - protected $executor; - /** - * @var string - */ - protected $id; - /** - * @var UselessFileDetector - */ - protected $fileDetector; - - /** - * @param RemoteExecuteMethod $executor - * @param string $id - */ - public function __construct(RemoteExecuteMethod $executor, $id) { - $this->executor = $executor; - $this->id = $id; - $this->fileDetector = new UselessFileDetector(); - } - - /** - * If this element is a TEXTAREA or text INPUT element, this will clear the - * value. - * - * @return RemoteWebElement The current instance. - */ - public function clear() { - $this->executor->execute( - DriverCommand::CLEAR_ELEMENT, - array(':id' => $this->id) - ); - return $this; - } - - /** - * Click this element. - * - * @return RemoteWebElement The current instance. - */ - public function click() { - $this->executor->execute( - DriverCommand::CLICK_ELEMENT, - array(':id' => $this->id) - ); - return $this; - } - - /** - * Find the first WebDriverElement within this element using the given - * mechanism. - * - * @param WebDriverBy $by - * @return RemoteWebElement NoSuchElementException is thrown in - * HttpCommandExecutor if no element is found. - * @see WebDriverBy - */ - public function findElement(WebDriverBy $by) { - $params = array( - 'using' => $by->getMechanism(), - 'value' => $by->getValue(), - ':id' => $this->id, - ); - $raw_element = $this->executor->execute( - DriverCommand::FIND_CHILD_ELEMENT, - $params - ); - - return $this->newElement($raw_element['ELEMENT']); - } - - /** - * Find all WebDriverElements within this element using the given mechanism. - * - * @param WebDriverBy $by - * @return RemoteWebElement[] A list of all WebDriverElements, or an empty - * array if nothing matches - * @see WebDriverBy - */ - public function findElements(WebDriverBy $by) { - $params = array( - 'using' => $by->getMechanism(), - 'value' => $by->getValue(), - ':id' => $this->id, - ); - $raw_elements = $this->executor->execute( - DriverCommand::FIND_CHILD_ELEMENTS, - $params - ); - - $elements = array(); - foreach ($raw_elements as $raw_element) { - $elements[] = $this->newElement($raw_element['ELEMENT']); +class RemoteWebElement implements WebDriverElement, WebDriverLocatable +{ + /** + * @var RemoteExecuteMethod + */ + protected $executor; + /** + * @var string + */ + protected $id; + /** + * @var UselessFileDetector + */ + protected $fileDetector; + + /** + * @param RemoteExecuteMethod $executor + * @param string $id + */ + public function __construct(RemoteExecuteMethod $executor, $id) + { + $this->executor = $executor; + $this->id = $id; + $this->fileDetector = new UselessFileDetector(); } - return $elements; - } - - /** - * Get the value of a the given attribute of the element. - * - * @param string $attribute_name The name of the attribute. - * @return string|null The value of the attribute. - */ - public function getAttribute($attribute_name) { - $params = array( - ':name' => $attribute_name, - ':id' => $this->id, - ); - return $this->executor->execute( - DriverCommand::GET_ELEMENT_ATTRIBUTE, - $params - ); - } - - /** - * Get the value of a given CSS property. - * - * @param string $css_property_name The name of the CSS property. - * @return string The value of the CSS property. - */ - public function getCSSValue($css_property_name) { - $params = array( - ':propertyName' => $css_property_name, - ':id' => $this->id, - ); - return $this->executor->execute( - DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY, - $params - ); - } - - /** - * Get the location of element relative to the top-left corner of the page. - * - * @return WebDriverPoint The location of the element. - */ - public function getLocation() { - $location = $this->executor->execute( - DriverCommand::GET_ELEMENT_LOCATION, - array(':id' => $this->id) - ); - return new WebDriverPoint($location['x'], $location['y']); - } - - /** - * Try scrolling the element into the view port and return the location of - * element relative to the top-left corner of the page afterwards. - * - * @return WebDriverPoint The location of the element. - */ - public function getLocationOnScreenOnceScrolledIntoView() { - $location = $this->executor->execute( - DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW, - array(':id' => $this->id) - ); - return new WebDriverPoint($location['x'], $location['y']); - } - - /** - * @return WebDriverCoordinates - */ - public function getCoordinates() { - $element = $this; - - $on_screen = null; // planned but not yet implemented - $in_view_port = function () use ($element) { - return $element->getLocationOnScreenOnceScrolledIntoView(); - }; - $on_page = function () use ($element) { - return $element->getLocation(); - }; - $auxiliary = $this->getID(); - - return new WebDriverCoordinates( - $on_screen, - $in_view_port, - $on_page, - $auxiliary - ); - } - - /** - * Get the size of element. - * - * @return WebDriverDimension The dimension of the element. - */ - public function getSize() { - $size = $this->executor->execute( - DriverCommand::GET_ELEMENT_SIZE, - array(':id' => $this->id) - ); - return new WebDriverDimension($size['width'], $size['height']); - } - - /** - * Get the tag name of this element. - * - * @return string The tag name. - */ - public function getTagName() { - // Force tag name to be lowercase as expected by protocol for Opera driver - // until this issue is not resolved : - // https://github.com/operasoftware/operadriver/issues/102 - // Remove it when fixed to be consistent with the protocol. - return strtolower($this->executor->execute( - DriverCommand::GET_ELEMENT_TAG_NAME, - array(':id' => $this->id) - )); - } - - /** - * Get the visible (i.e. not hidden by CSS) innerText of this element, - * including sub-elements, without any leading or trailing whitespace. - * - * @return string The visible innerText of this element. - */ - public function getText() { - return $this->executor->execute( - DriverCommand::GET_ELEMENT_TEXT, - array(':id' => $this->id) - ); - } - - /** - * Is this element displayed or not? This method avoids the problem of having - * to parse an element's "style" attribute. - * - * @return bool - */ - public function isDisplayed() { - return $this->executor->execute( - DriverCommand::IS_ELEMENT_DISPLAYED, - array(':id' => $this->id) - ); - } - - /** - * Is the element currently enabled or not? This will generally return true - * for everything but disabled input elements. - * - * @return bool - */ - public function isEnabled() { - return $this->executor->execute( - DriverCommand::IS_ELEMENT_ENABLED, - array(':id' => $this->id) - ); - } - - /** - * Determine whether or not this element is selected or not. - * - * @return bool - */ - public function isSelected() { - return $this->executor->execute( - DriverCommand::IS_ELEMENT_SELECTED, - array(':id' => $this->id) - ); - } - - /** - * Simulate typing into an element, which may set its value. - * - * @param mixed $value The data to be typed. - * @return RemoteWebElement The current instance. - */ - public function sendKeys($value) { - $local_file = $this->fileDetector->getLocalFile($value); - if ($local_file === null) { - $params = array( - 'value' => WebDriverKeys::encode($value), - ':id' => $this->id, - ); - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); - } else { - $remote_path = $this->upload($local_file); - $params = array( - 'value' => WebDriverKeys::encode($remote_path), - ':id' => $this->id, - ); - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); + + /** + * If this element is a TEXTAREA or text INPUT element, this will clear the + * value. + * + * @return RemoteWebElement The current instance. + */ + public function clear() + { + $this->executor->execute( + DriverCommand::CLEAR_ELEMENT, + array(':id' => $this->id) + ); + + return $this; + } + + /** + * Click this element. + * + * @return RemoteWebElement The current instance. + */ + public function click() + { + $this->executor->execute( + DriverCommand::CLICK_ELEMENT, + array(':id' => $this->id) + ); + + return $this; + } + + /** + * Find the first WebDriverElement within this element using the given + * mechanism. + * + * @param WebDriverBy $by + * @return RemoteWebElement NoSuchElementException is thrown in + * HttpCommandExecutor if no element is found. + * @see WebDriverBy + */ + public function findElement(WebDriverBy $by) + { + $params = array( + 'using' => $by->getMechanism(), + 'value' => $by->getValue(), + ':id' => $this->id, + ); + $raw_element = $this->executor->execute( + DriverCommand::FIND_CHILD_ELEMENT, + $params + ); + + return $this->newElement($raw_element['ELEMENT']); + } + + /** + * Find all WebDriverElements within this element using the given mechanism. + * + * @param WebDriverBy $by + * @return RemoteWebElement[] A list of all WebDriverElements, or an empty + * array if nothing matches + * @see WebDriverBy + */ + public function findElements(WebDriverBy $by) + { + $params = array( + 'using' => $by->getMechanism(), + 'value' => $by->getValue(), + ':id' => $this->id, + ); + $raw_elements = $this->executor->execute( + DriverCommand::FIND_CHILD_ELEMENTS, + $params + ); + + $elements = array(); + foreach ($raw_elements as $raw_element) { + $elements[] = $this->newElement($raw_element['ELEMENT']); + } + + return $elements; + } + + /** + * Get the value of a the given attribute of the element. + * + * @param string $attribute_name The name of the attribute. + * @return string|null The value of the attribute. + */ + public function getAttribute($attribute_name) + { + $params = array( + ':name' => $attribute_name, + ':id' => $this->id, + ); + + return $this->executor->execute( + DriverCommand::GET_ELEMENT_ATTRIBUTE, + $params + ); + } + + /** + * Get the value of a given CSS property. + * + * @param string $css_property_name The name of the CSS property. + * @return string The value of the CSS property. + */ + public function getCSSValue($css_property_name) + { + $params = array( + ':propertyName' => $css_property_name, + ':id' => $this->id, + ); + + return $this->executor->execute( + DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY, + $params + ); + } + + /** + * Get the location of element relative to the top-left corner of the page. + * + * @return WebDriverPoint The location of the element. + */ + public function getLocation() + { + $location = $this->executor->execute( + DriverCommand::GET_ELEMENT_LOCATION, + array(':id' => $this->id) + ); + + return new WebDriverPoint($location['x'], $location['y']); + } + + /** + * Try scrolling the element into the view port and return the location of + * element relative to the top-left corner of the page afterwards. + * + * @return WebDriverPoint The location of the element. + */ + public function getLocationOnScreenOnceScrolledIntoView() + { + $location = $this->executor->execute( + DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW, + array(':id' => $this->id) + ); + + return new WebDriverPoint($location['x'], $location['y']); + } + + /** + * @return WebDriverCoordinates + */ + public function getCoordinates() + { + $element = $this; + + $on_screen = null; // planned but not yet implemented + $in_view_port = function () use ($element) { + return $element->getLocationOnScreenOnceScrolledIntoView(); + }; + $on_page = function () use ($element) { + return $element->getLocation(); + }; + $auxiliary = $this->getID(); + + return new WebDriverCoordinates( + $on_screen, + $in_view_port, + $on_page, + $auxiliary + ); + } + + /** + * Get the size of element. + * + * @return WebDriverDimension The dimension of the element. + */ + public function getSize() + { + $size = $this->executor->execute( + DriverCommand::GET_ELEMENT_SIZE, + array(':id' => $this->id) + ); + + return new WebDriverDimension($size['width'], $size['height']); + } + + /** + * Get the tag name of this element. + * + * @return string The tag name. + */ + public function getTagName() + { + // Force tag name to be lowercase as expected by protocol for Opera driver + // until this issue is not resolved : + // https://github.com/operasoftware/operadriver/issues/102 + // Remove it when fixed to be consistent with the protocol. + return strtolower($this->executor->execute( + DriverCommand::GET_ELEMENT_TAG_NAME, + array(':id' => $this->id) + )); + } + + /** + * Get the visible (i.e. not hidden by CSS) innerText of this element, + * including sub-elements, without any leading or trailing whitespace. + * + * @return string The visible innerText of this element. + */ + public function getText() + { + return $this->executor->execute( + DriverCommand::GET_ELEMENT_TEXT, + array(':id' => $this->id) + ); + } + + /** + * Is this element displayed or not? This method avoids the problem of having + * to parse an element's "style" attribute. + * + * @return bool + */ + public function isDisplayed() + { + return $this->executor->execute( + DriverCommand::IS_ELEMENT_DISPLAYED, + array(':id' => $this->id) + ); + } + + /** + * Is the element currently enabled or not? This will generally return true + * for everything but disabled input elements. + * + * @return bool + */ + public function isEnabled() + { + return $this->executor->execute( + DriverCommand::IS_ELEMENT_ENABLED, + array(':id' => $this->id) + ); + } + + /** + * Determine whether or not this element is selected or not. + * + * @return bool + */ + public function isSelected() + { + return $this->executor->execute( + DriverCommand::IS_ELEMENT_SELECTED, + array(':id' => $this->id) + ); + } + + /** + * Simulate typing into an element, which may set its value. + * + * @param mixed $value The data to be typed. + * @return RemoteWebElement The current instance. + */ + public function sendKeys($value) + { + $local_file = $this->fileDetector->getLocalFile($value); + if ($local_file === null) { + $params = array( + 'value' => WebDriverKeys::encode($value), + ':id' => $this->id, + ); + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); + } else { + $remote_path = $this->upload($local_file); + $params = array( + 'value' => WebDriverKeys::encode($remote_path), + ':id' => $this->id, + ); + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); + } + + return $this; + } + + /** + * Upload a local file to the server + * + * @param string $local_file + * + * @throws WebDriverException + * @return string The remote path of the file. + */ + private function upload($local_file) + { + if (!is_file($local_file)) { + throw new WebDriverException('You may only upload files: ' . $local_file); + } + + // Create a temporary file in the system temp directory. + $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip'); + $zip = new ZipArchive(); + if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) { + return false; + } + $info = pathinfo($local_file); + $file_name = $info['basename']; + $zip->addFile($local_file, $file_name); + $zip->close(); + $params = array( + 'file' => base64_encode(file_get_contents($temp_zip)), + ); + $remote_path = $this->executor->execute( + DriverCommand::UPLOAD_FILE, + $params + ); + unlink($temp_zip); + + return $remote_path; + } + + /** + * Set the fileDetector in order to let the RemoteWebElement to know that + * you are going to upload a file. + * + * Basically, if you want WebDriver trying to send a file, set the fileDetector + * to be LocalFileDetector. Otherwise, keep it UselessFileDetector. + * + * eg. $element->setFileDetector(new LocalFileDetector); + * + * @param FileDetector $detector + * @return RemoteWebElement + * @see FileDetector + * @see LocalFileDetector + * @see UselessFileDetector + */ + public function setFileDetector(FileDetector $detector) + { + $this->fileDetector = $detector; + + return $this; } - return $this; - } - - /** - * Upload a local file to the server - * - * @param string $local_file - * - * @throws WebDriverException - * @return string The remote path of the file. - */ - private function upload($local_file) { - if (!is_file($local_file)) { - throw new WebDriverException("You may only upload files: " . $local_file); + + /** + * If this current element is a form, or an element within a form, then this + * will be submitted to the remote server. + * + * @return RemoteWebElement The current instance. + */ + public function submit() + { + $this->executor->execute( + DriverCommand::SUBMIT_ELEMENT, + array(':id' => $this->id) + ); + + return $this; + } + + /** + * Get the opaque ID of the element. + * + * @return string The opaque ID. + */ + public function getID() + { + return $this->id; + } + + /** + * Test if two element IDs refer to the same DOM element. + * + * @param WebDriverElement $other + * @return bool + */ + public function equals(WebDriverElement $other) + { + return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, array( + ':id' => $this->id, + ':other' => $other->getID(), + )); } - // Create a temporary file in the system temp directory. - $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip'); - $zip = new ZipArchive(); - if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) { - return false; + /** + * Return the WebDriverElement with $id + * + * @param string $id + * + * @return RemoteWebElement + */ + protected function newElement($id) + { + return new static($this->executor, $id); } - $info = pathinfo($local_file); - $file_name = $info['basename']; - $zip->addFile($local_file, $file_name); - $zip->close(); - $params = array( - 'file' => base64_encode(file_get_contents($temp_zip)), - ); - $remote_path = $this->executor->execute( - DriverCommand::UPLOAD_FILE, - $params - ); - unlink($temp_zip); - return $remote_path; - } - - /** - * Set the fileDetector in order to let the RemoteWebElement to know that - * you are going to upload a file. - * - * Basically, if you want WebDriver trying to send a file, set the fileDetector - * to be LocalFileDetector. Otherwise, keep it UselessFileDetector. - * - * eg. $element->setFileDetector(new LocalFileDetector); - * - * @param FileDetector $detector - * @return RemoteWebElement - * @see FileDetector - * @see LocalFileDetector - * @see UselessFileDetector - */ - public function setFileDetector(FileDetector $detector) { - $this->fileDetector = $detector; - return $this; - } - - /** - * If this current element is a form, or an element within a form, then this - * will be submitted to the remote server. - * - * @return RemoteWebElement The current instance. - */ - public function submit() { - $this->executor->execute( - DriverCommand::SUBMIT_ELEMENT, - array(':id' => $this->id) - ); - - return $this; - } - - /** - * Get the opaque ID of the element. - * - * @return string The opaque ID. - */ - public function getID() { - return $this->id; - } - - /** - * Test if two element IDs refer to the same DOM element. - * - * @param WebDriverElement $other - * @return bool - */ - public function equals(WebDriverElement $other) { - return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, array( - ':id' => $this->id, - ':other' => $other->getID(), - )); - } - - /** - * Return the WebDriverElement with $id - * - * @param string $id - * - * @return RemoteWebElement - */ - protected function newElement($id) { - return new static($this->executor, $id); - } } diff --git a/lib/Remote/Service/DriverCommandExecutor.php b/lib/Remote/Service/DriverCommandExecutor.php index 2ac3414f1..59125833b 100644 --- a/lib/Remote/Service/DriverCommandExecutor.php +++ b/lib/Remote/Service/DriverCommandExecutor.php @@ -24,42 +24,44 @@ * A HttpCommandExecutor that talks to a local driver service instead of * a remote server. */ -class DriverCommandExecutor extends HttpCommandExecutor { +class DriverCommandExecutor extends HttpCommandExecutor +{ + /** + * @var DriverService + */ + private $service; - /** - * @var DriverService - */ - private $service; + public function __construct(DriverService $service) + { + parent::__construct($service->getURL()); + $this->service = $service; + } - public function __construct(DriverService $service) { - parent::__construct($service->getURL()); - $this->service = $service; - } + /** + * @param WebDriverCommand $command + * + * @throws WebDriverException + * @throws \Exception + * @return mixed + */ + public function execute(WebDriverCommand $command) + { + if ($command->getName() === DriverCommand::NEW_SESSION) { + $this->service->start(); + } - /** - * @param WebDriverCommand $command - * - * @return mixed - * @throws WebDriverException - * @throws \Exception - */ - public function execute(WebDriverCommand $command) { - if ($command->getName() === DriverCommand::NEW_SESSION) { - $this->service->start(); - } + try { + $value = parent::execute($command); + if ($command->getName() === DriverCommand::QUIT) { + $this->service->stop(); + } - try { - $value = parent::execute($command); - if ($command->getName() === DriverCommand::QUIT) { - $this->service->stop(); - } - return $value; - } catch (\Exception $e) { - if (!$this->service->isRunning()) { - throw new WebDriverException('The driver server has died.'); - } - throw $e; + return $value; + } catch (\Exception $e) { + if (!$this->service->isRunning()) { + throw new WebDriverException('The driver server has died.'); + } + throw $e; + } } - } - } diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index 8a18e5d5d..82a427a44 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -18,130 +18,132 @@ use Exception; use Facebook\WebDriver\Net\URLChecker; -class DriverService { - - /** - * @var string - */ - private $executable; - - /** - * @var string - */ - private $url; - - /** - * @var array - */ - private $args; - - /** - * @var array - */ - private $environment; - - /** - * @var resource - */ - private $process; - - /** - * @param string $executable - * @param int $port The given port the service should use. - * @param array $args - * @param array|null $environment Use the system environment if it is null - */ - public function __construct( - $executable, - $port, - $args = array(), - $environment = null - ) { - $this->executable = self::checkExecutable($executable); - $this->url = sprintf('http://localhost:%d', $port); - $this->args = $args; - $this->environment = $environment ?: $_ENV; - } - - /** - * @return string - */ - public function getURL() { - return $this->url; - } - - /** - * @return DriverService - */ - public function start() { - if ($this->process !== null) { - return $this; +class DriverService +{ + /** + * @var string + */ + private $executable; + + /** + * @var string + */ + private $url; + + /** + * @var array + */ + private $args; + + /** + * @var array + */ + private $environment; + + /** + * @var resource + */ + private $process; + + /** + * @param string $executable + * @param int $port The given port the service should use. + * @param array $args + * @param array|null $environment Use the system environment if it is null + */ + public function __construct($executable, $port, $args = array(), $environment = null) + { + $this->executable = self::checkExecutable($executable); + $this->url = sprintf('http://localhost:%d', $port); + $this->args = $args; + $this->environment = $environment ?: $_ENV; } - $pipes = array(); - $this->process = proc_open( - sprintf("%s %s", $this->executable, implode(' ', $this->args)), - $descriptorspec = array( - 0 => array('pipe', 'r'), // stdin - 1 => array('pipe', 'w'), // stdout - 2 => array('pipe', 'a'), // stderr - ), - $pipes, - null, - $this->environment - ); - - $checker = new URLChecker(); - $checker->waitUntilAvailable(20 * 1000, $this->url.'/status'); - - return $this; - } - - /** - * @return DriverService - */ - public function stop() { - if ($this->process === null) { - return $this; + /** + * @return string + */ + public function getURL() + { + return $this->url; } - proc_terminate($this->process); - $this->process = null; + /** + * @return DriverService + */ + public function start() + { + if ($this->process !== null) { + return $this; + } + + $pipes = array(); + $this->process = proc_open( + sprintf('%s %s', $this->executable, implode(' ', $this->args)), + $descriptorspec = array( + 0 => array('pipe', 'r'), // stdin + 1 => array('pipe', 'w'), // stdout + 2 => array('pipe', 'a'), // stderr + ), + $pipes, + null, + $this->environment + ); + + $checker = new URLChecker(); + $checker->waitUntilAvailable(20 * 1000, $this->url . '/status'); + + return $this; + } - $checker = new URLChecker(); - $checker->waitUntilUnavailable(3 * 1000, $this->url.'/shutdown'); + /** + * @return DriverService + */ + public function stop() + { + if ($this->process === null) { + return $this; + } - return $this; - } + proc_terminate($this->process); + $this->process = null; - /** - * @return bool - */ - public function isRunning() { - if ($this->process === null) { - return false; - } + $checker = new URLChecker(); + $checker->waitUntilUnavailable(3 * 1000, $this->url . '/shutdown'); - $status = proc_get_status($this->process); - return $status['running']; - } - - /** - * Check if the executable is executable. - * - * @param string $executable - * @return string - * @throws Exception - */ - protected static function checkExecutable($executable) { - if (!is_file($executable)) { - throw new Exception("'$executable' is not a file."); + return $this; } - if (!is_executable($executable)) { - throw new Exception("'$executable' is not executable."); + /** + * @return bool + */ + public function isRunning() + { + if ($this->process === null) { + return false; + } + + $status = proc_get_status($this->process); + + return $status['running']; } - return $executable; - } + /** + * Check if the executable is executable. + * + * @param string $executable + * @throws Exception + * @return string + */ + protected static function checkExecutable($executable) + { + if (!is_file($executable)) { + throw new Exception("'$executable' is not a file."); + } + + if (!is_executable($executable)) { + throw new Exception("'$executable' is not executable."); + } + + return $executable; + } } diff --git a/lib/Remote/UselessFileDetector.php b/lib/Remote/UselessFileDetector.php index 9a8090038..f1e71f0c5 100644 --- a/lib/Remote/UselessFileDetector.php +++ b/lib/Remote/UselessFileDetector.php @@ -15,13 +15,13 @@ namespace Facebook\WebDriver\Remote; -class UselessFileDetector implements FileDetector { - /** - * @param string $file - * - * @return null - */ - public function getLocalFile($file) { - return null; - } +class UselessFileDetector implements FileDetector +{ + /** + * @param string $file + */ + public function getLocalFile($file) + { + return null; + } } diff --git a/lib/Remote/WebDriverBrowserType.php b/lib/Remote/WebDriverBrowserType.php index a9de79143..977662a4a 100644 --- a/lib/Remote/WebDriverBrowserType.php +++ b/lib/Remote/WebDriverBrowserType.php @@ -18,31 +18,31 @@ /** * All the browsers supported by selenium */ -class WebDriverBrowserType { - const FIREFOX = "firefox"; - const FIREFOX_2 = "firefox2"; - const FIREFOX_3 = "firefox3"; - const FIREFOX_PROXY = "firefoxproxy"; - const FIREFOX_CHROME = "firefoxchrome"; - const GOOGLECHROME = "googlechrome"; - const SAFARI = "safari"; - const OPERA = "opera"; - const IEXPLORE= "iexplore"; - const IEXPLORE_PROXY= "iexploreproxy"; - const SAFARI_PROXY = "safariproxy"; - const CHROME = "chrome"; - const KONQUEROR = "konqueror"; - const MOCK = "mock"; - const IE_HTA="iehta"; +class WebDriverBrowserType +{ + const FIREFOX = 'firefox'; + const FIREFOX_2 = 'firefox2'; + const FIREFOX_3 = 'firefox3'; + const FIREFOX_PROXY = 'firefoxproxy'; + const FIREFOX_CHROME = 'firefoxchrome'; + const GOOGLECHROME = 'googlechrome'; + const SAFARI = 'safari'; + const OPERA = 'opera'; + const IEXPLORE = 'iexplore'; + const IEXPLORE_PROXY = 'iexploreproxy'; + const SAFARI_PROXY = 'safariproxy'; + const CHROME = 'chrome'; + const KONQUEROR = 'konqueror'; + const MOCK = 'mock'; + const IE_HTA = 'iehta'; + const ANDROID = 'android'; + const HTMLUNIT = 'htmlunit'; + const IE = 'internet explorer'; + const IPHONE = 'iphone'; + const IPAD = 'iPad'; + const PHANTOMJS = 'phantomjs'; - const ANDROID = "android"; - const HTMLUNIT = "htmlunit"; - const IE = "internet explorer"; - const IPHONE = "iphone"; - const IPAD = "iPad"; - const PHANTOMJS = "phantomjs"; - - private function __construct() - { - } + private function __construct() + { + } } diff --git a/lib/Remote/WebDriverCapabilityType.php b/lib/Remote/WebDriverCapabilityType.php index 459952364..131b16561 100644 --- a/lib/Remote/WebDriverCapabilityType.php +++ b/lib/Remote/WebDriverCapabilityType.php @@ -18,25 +18,26 @@ /** * WebDriverCapabilityType contains all constants defined in the WebDriver Wire Protocol. */ -class WebDriverCapabilityType { - const BROWSER_NAME = 'browserName'; - const VERSION = 'version'; - const PLATFORM = 'platform'; - const JAVASCRIPT_ENABLED = 'javascriptEnabled'; - const TAKES_SCREENSHOT = 'takesScreenshot'; - const HANDLES_ALERTS = 'handlesAlerts'; - const DATABASE_ENABLED = 'databaseEnabled'; - const LOCATION_CONTEXT_ENABLED = 'locationContextEnabled'; - const APPLICATION_CACHE_ENABLED = 'applicationCacheEnabled'; - const BROWSER_CONNECTION_ENABLED = 'browserConnectionEnabled'; - const CSS_SELECTORS_ENABLED = 'cssSelectorsEnabled'; - const WEB_STORAGE_ENABLED = 'webStorageEnabled'; - const ROTATABLE = 'rotatable'; - const ACCEPT_SSL_CERTS = 'acceptSslCerts'; - const NATIVE_EVENTS = 'nativeEvents'; - const PROXY = 'proxy'; +class WebDriverCapabilityType +{ + const BROWSER_NAME = 'browserName'; + const VERSION = 'version'; + const PLATFORM = 'platform'; + const JAVASCRIPT_ENABLED = 'javascriptEnabled'; + const TAKES_SCREENSHOT = 'takesScreenshot'; + const HANDLES_ALERTS = 'handlesAlerts'; + const DATABASE_ENABLED = 'databaseEnabled'; + const LOCATION_CONTEXT_ENABLED = 'locationContextEnabled'; + const APPLICATION_CACHE_ENABLED = 'applicationCacheEnabled'; + const BROWSER_CONNECTION_ENABLED = 'browserConnectionEnabled'; + const CSS_SELECTORS_ENABLED = 'cssSelectorsEnabled'; + const WEB_STORAGE_ENABLED = 'webStorageEnabled'; + const ROTATABLE = 'rotatable'; + const ACCEPT_SSL_CERTS = 'acceptSslCerts'; + const NATIVE_EVENTS = 'nativeEvents'; + const PROXY = 'proxy'; - private function __construct() - { - } + private function __construct() + { + } } diff --git a/lib/Remote/WebDriverCommand.php b/lib/Remote/WebDriverCommand.php index cb90d2b64..b801b0645 100644 --- a/lib/Remote/WebDriverCommand.php +++ b/lib/Remote/WebDriverCommand.php @@ -15,43 +15,48 @@ namespace Facebook\WebDriver\Remote; -class WebDriverCommand { - /** @var string */ - private $sessionID; - /** @var string */ - private $name; - /** @var array */ - private $parameters; +class WebDriverCommand +{ + /** @var string */ + private $sessionID; + /** @var string */ + private $name; + /** @var array */ + private $parameters; - /** - * @param string $session_id - * @param string $name Constant from DriverCommand - * @param array $parameters Array of - */ - public function __construct($session_id, $name, $parameters) { - $this->sessionID = $session_id; - $this->name = $name; - $this->parameters = $parameters; - } + /** + * @param string $session_id + * @param string $name Constant from DriverCommand + * @param array $parameters Array of + */ + public function __construct($session_id, $name, $parameters) + { + $this->sessionID = $session_id; + $this->name = $name; + $this->parameters = $parameters; + } - /** - * @return string - */ - public function getName() { - return $this->name; - } + /** + * @return string + */ + public function getName() + { + return $this->name; + } - /** - * @return string - */ - public function getSessionID() { - return $this->sessionID; - } + /** + * @return string + */ + public function getSessionID() + { + return $this->sessionID; + } - /** - * @return array - */ - public function getParameters() { - return $this->parameters; - } + /** + * @return array + */ + public function getParameters() + { + return $this->parameters; + } } diff --git a/lib/Remote/WebDriverResponse.php b/lib/Remote/WebDriverResponse.php index d3fcdadcb..92ac6f66d 100644 --- a/lib/Remote/WebDriverResponse.php +++ b/lib/Remote/WebDriverResponse.php @@ -15,75 +15,83 @@ namespace Facebook\WebDriver\Remote; -class WebDriverResponse { +class WebDriverResponse +{ + /** + * @var int + */ + private $status; + /** + * @var mixed + */ + private $value; + /** + * @var string + */ + private $sessionID; - /** - * @var int - */ - private $status; + /** + * @param null|string $session_id + */ + public function __construct($session_id = null) + { + $this->sessionID = $session_id; + } - /** - * @var mixed - */ - private $value; + /** + * @return null|int + */ + public function getStatus() + { + return $this->status; + } - /** - * @var string - */ - private $sessionID; + /** + * @param int $status + * @return WebDriverResponse + */ + public function setStatus($status) + { + $this->status = $status; - /** - * @param null|string $session_id - */ - public function __construct($session_id = null) { - $this->sessionID = $session_id; - } + return $this; + } - /** - * @return null|int - */ - public function getStatus() { - return $this->status; - } + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } - /** - * @param int $status - * @return WebDriverResponse - */ - public function setStatus($status) { - $this->status = $status; - return $this; - } + /** + * @param mixed $value + * @return WebDriverResponse + */ + public function setValue($value) + { + $this->value = $value; - /** - * @return mixed - */ - public function getValue() { - return $this->value; - } + return $this; + } - /** - * @param mixed $value - * @return WebDriverResponse - */ - public function setValue($value) { - $this->value = $value; - return $this; - } + /** + * @return null|string + */ + public function getSessionID() + { + return $this->sessionID; + } - /** - * @return null|string - */ - public function getSessionID() { - return $this->sessionID; - } + /** + * @param mixed $session_id + * @return WebDriverResponse + */ + public function setSessionID($session_id) + { + $this->sessionID = $session_id; - /** - * @param mixed $session_id - * @return WebDriverResponse - */ - public function setSessionID($session_id) { - $this->sessionID = $session_id; - return $this; - } + return $this; + } } diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index ab279cb1d..7ea2242b0 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -27,339 +27,367 @@ use Facebook\WebDriver\WebDriverTargetLocator; use Facebook\WebDriver\WebDriverWait; -class EventFiringWebDriver implements WebDriver, JavaScriptExecutor { - - /** - * @var WebDriver - */ - protected $driver; - - /** - * @var WebDriverDispatcher - */ - protected $dispatcher; - - /** - * @param WebDriver $driver - * @param WebDriverDispatcher $dispatcher - */ - public function __construct(WebDriver $driver, - WebDriverDispatcher $dispatcher = null) { - $this->dispatcher = $dispatcher ?: new WebDriverDispatcher(); - if (!$this->dispatcher->getDefaultDriver()) { - $this->dispatcher->setDefaultDriver($this); +class EventFiringWebDriver implements WebDriver, JavaScriptExecutor +{ + /** + * @var WebDriver + */ + protected $driver; + + /** + * @var WebDriverDispatcher + */ + protected $dispatcher; + + /** + * @param WebDriver $driver + * @param WebDriverDispatcher $dispatcher + */ + public function __construct(WebDriver $driver, WebDriverDispatcher $dispatcher = null) + { + $this->dispatcher = $dispatcher ?: new WebDriverDispatcher(); + if (!$this->dispatcher->getDefaultDriver()) { + $this->dispatcher->setDefaultDriver($this); + } + $this->driver = $driver; + + return $this; } - $this->driver = $driver; - return $this; - } - - /** - * @return WebDriverDispatcher - */ - public function getDispatcher() { - return $this->dispatcher; - } - - /** - * @param mixed $method - * @return void - */ - protected function dispatch($method) { - if (!$this->dispatcher) { - return; + + /** + * @return WebDriverDispatcher + */ + public function getDispatcher() + { + return $this->dispatcher; } - $arguments = func_get_args(); - unset($arguments[0]); - $this->dispatcher->dispatch($method, $arguments); - } - - /** - * @return WebDriver - */ - public function getWebDriver() { - return $this->driver; - } - - /** - * @param WebDriverElement $element - * @return EventFiringWebElement - */ - protected function newElement(WebDriverElement $element) { - return new EventFiringWebElement($element, $this->getDispatcher()); - } - - /** - * @param mixed $url - * @return $this - * @throws WebDriverException - */ - public function get($url) { - $this->dispatch('beforeNavigateTo', $url, $this); - try { - $this->driver->get($url); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + /** + * @param mixed $method + */ + protected function dispatch($method) + { + if (!$this->dispatcher) { + return; + } + + $arguments = func_get_args(); + unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); } - $this->dispatch('afterNavigateTo', $url, $this); - return $this; - } - - /** - * @param WebDriverBy $by - * @return array - * @throws WebDriverException - */ - public function findElements(WebDriverBy $by) { - $this->dispatch('beforeFindBy', $by, null, $this); - try { - $elements = array(); - foreach ($this->driver->findElements($by) as $element) { - $elements[] = $this->newElement($element); - } - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @return WebDriver + */ + public function getWebDriver() + { + return $this->driver; } - $this->dispatch('afterFindBy', $by, null, $this); - return $elements; - - } - - /** - * @param WebDriverBy $by - * @return EventFiringWebElement - * @throws WebDriverException - */ - public function findElement(WebDriverBy $by) { - $this->dispatch('beforeFindBy', $by, null, $this); - try { - $element = $this->newElement($this->driver->findElement($by)); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param WebDriverElement $element + * @return EventFiringWebElement + */ + protected function newElement(WebDriverElement $element) + { + return new EventFiringWebElement($element, $this->getDispatcher()); } - $this->dispatch('afterFindBy', $by, null, $this); - return $element; - } - - /** - * @param $script - * @param array $arguments - * @return mixed - * @throws WebDriverException - */ - public function executeScript($script, array $arguments = array()) { - if (!$this->driver instanceof JavaScriptExecutor) { - throw new UnsupportedOperationException( - 'driver does not implement JavaScriptExecutor' - ); + + /** + * @param mixed $url + * @throws WebDriverException + * @return $this + */ + public function get($url) + { + $this->dispatch('beforeNavigateTo', $url, $this); + try { + $this->driver->get($url); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterNavigateTo', $url, $this); + + return $this; } - $this->dispatch('beforeScript', $script, $this); - try { - $result = $this->driver->executeScript($script, $arguments); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + /** + * @param WebDriverBy $by + * @throws WebDriverException + * @return array + */ + public function findElements(WebDriverBy $by) + { + $this->dispatch('beforeFindBy', $by, null, $this); + try { + $elements = array(); + foreach ($this->driver->findElements($by) as $element) { + $elements[] = $this->newElement($element); + } + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterFindBy', $by, null, $this); + + return $elements; } - $this->dispatch('afterScript', $script, $this); - return $result; - } - - /** - * @param $script - * @param array $arguments - * @return mixed - * @throws WebDriverException - */ - public function executeAsyncScript($script, array $arguments = array()) { - if (!$this->driver instanceof JavaScriptExecutor) { - throw new UnsupportedOperationException( - 'driver does not implement JavaScriptExecutor' - ); + + /** + * @param WebDriverBy $by + * @throws WebDriverException + * @return EventFiringWebElement + */ + public function findElement(WebDriverBy $by) + { + $this->dispatch('beforeFindBy', $by, null, $this); + try { + $element = $this->newElement($this->driver->findElement($by)); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterFindBy', $by, null, $this); + + return $element; } - $this->dispatch('beforeScript', $script, $this); - try { - $result = $this->driver->executeAsyncScript($script, $arguments); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + /** + * @param $script + * @param array $arguments + * @throws WebDriverException + * @return mixed + */ + public function executeScript($script, array $arguments = array()) + { + if (!$this->driver instanceof JavaScriptExecutor) { + throw new UnsupportedOperationException( + 'driver does not implement JavaScriptExecutor' + ); + } + + $this->dispatch('beforeScript', $script, $this); + try { + $result = $this->driver->executeScript($script, $arguments); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterScript', $script, $this); + + return $result; } - $this->dispatch('afterScript', $script, $this); - return $result; - } - - /** - * @return $this - * @throws WebDriverException - */ - public function close() { - try { - $this->driver->close(); - return $this; - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param $script + * @param array $arguments + * @throws WebDriverException + * @return mixed + */ + public function executeAsyncScript($script, array $arguments = array()) + { + if (!$this->driver instanceof JavaScriptExecutor) { + throw new UnsupportedOperationException( + 'driver does not implement JavaScriptExecutor' + ); + } + + $this->dispatch('beforeScript', $script, $this); + try { + $result = $this->driver->executeAsyncScript($script, $arguments); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterScript', $script, $this); + + return $result; } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getCurrentURL() { - try { - return $this->driver->getCurrentURL(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return $this + */ + public function close() + { + try { + $this->driver->close(); + + return $this; + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getPageSource() { - try { - return $this->driver->getPageSource(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return string + */ + public function getCurrentURL() + { + try { + return $this->driver->getCurrentURL(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getTitle() { - try { - return $this->driver->getTitle(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return string + */ + public function getPageSource() + { + try { + return $this->driver->getPageSource(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getWindowHandle() { - try { - return $this->driver->getWindowHandle(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return string + */ + public function getTitle() + { + try { + return $this->driver->getTitle(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return array - * @throws WebDriverException - */ - public function getWindowHandles() { - try { - return $this->driver->getWindowHandles(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return string + */ + public function getWindowHandle() + { + try { + return $this->driver->getWindowHandle(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @throws WebDriverException - */ - public function quit() { - try { - $this->driver->quit(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return array + */ + public function getWindowHandles() + { + try { + return $this->driver->getWindowHandles(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @param null|string $save_as - * @return string - * @throws WebDriverException - */ - public function takeScreenshot($save_as = null) { - try { - return $this->driver->takeScreenshot($save_as); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + */ + public function quit() + { + try { + $this->driver->quit(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @param int $timeout_in_second - * @param int $interval_in_millisecond - * @return WebDriverWait - * @throws WebDriverException - */ - public function wait($timeout_in_second = 30, - $interval_in_millisecond = 250) { - try { - return $this->driver->wait($timeout_in_second, $interval_in_millisecond); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param null|string $save_as + * @throws WebDriverException + * @return string + */ + public function takeScreenshot($save_as = null) + { + try { + return $this->driver->takeScreenshot($save_as); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return WebDriverOptions - * @throws WebDriverException - */ - public function manage() { - try { - return $this->driver->manage(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param int $timeout_in_second + * @param int $interval_in_millisecond + * @throws WebDriverException + * @return WebDriverWait + */ + public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) + { + try { + return $this->driver->wait($timeout_in_second, $interval_in_millisecond); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return EventFiringWebDriverNavigation - * @throws WebDriverException - */ - public function navigate() { - try { - return new EventFiringWebDriverNavigation( - $this->driver->navigate(), - $this->getDispatcher() - ); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return WebDriverOptions + */ + public function manage() + { + try { + return $this->driver->manage(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return WebDriverTargetLocator - * @throws WebDriverException - */ - public function switchTo() { - try { - return $this->driver->switchTo(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return EventFiringWebDriverNavigation + */ + public function navigate() + { + try { + return new EventFiringWebDriverNavigation( + $this->driver->navigate(), + $this->getDispatcher() + ); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return WebDriverTouchScreen - * @throws WebDriverException - */ - public function getTouch() { - try { - return $this->driver->getTouch(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return WebDriverTargetLocator + */ + public function switchTo() + { + try { + return $this->driver->switchTo(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - private function dispatchOnException($exception) { - $this->dispatch('onException', $exception, $this); - throw $exception; - } - - public function execute($name, $params) { - try { - return $this->driver->execute($name, $params); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return WebDriverTouchScreen + */ + public function getTouch() + { + try { + return $this->driver->getTouch(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + } + + private function dispatchOnException($exception) + { + $this->dispatch('onException', $exception, $this); + throw $exception; + } + + public function execute($name, $params) + { + try { + return $this->driver->execute($name, $params); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } } diff --git a/lib/Support/Events/EventFiringWebDriverNavigation.php b/lib/Support/Events/EventFiringWebDriverNavigation.php index 56341e2c2..a588d5e17 100644 --- a/lib/Support/Events/EventFiringWebDriverNavigation.php +++ b/lib/Support/Events/EventFiringWebDriverNavigation.php @@ -19,138 +19,149 @@ use Facebook\WebDriver\WebDriverDispatcher; use Facebook\WebDriver\WebDriverNavigation; -class EventFiringWebDriverNavigation { - - /** - * @var WebDriverNavigation - */ - protected $navigator; - - /** - * @var WebDriverDispatcher - */ - protected $dispatcher; - - /** - * @param WebDriverNavigation $navigator - * @param WebDriverDispatcher $dispatcher - */ - public function __construct(WebDriverNavigation $navigator, - WebDriverDispatcher $dispatcher) { - $this->navigator = $navigator; - $this->dispatcher = $dispatcher; - return $this; - } - - /** - * @return WebDriverDispatcher - */ - public function getDispatcher() { - return $this->dispatcher; - } - - /** - * @param mixed $method - * @return void - */ - protected function dispatch($method) { - if (!$this->dispatcher) { - return; +class EventFiringWebDriverNavigation +{ + /** + * @var WebDriverNavigation + */ + protected $navigator; + /** + * @var WebDriverDispatcher + */ + protected $dispatcher; + + /** + * @param WebDriverNavigation $navigator + * @param WebDriverDispatcher $dispatcher + */ + public function __construct(WebDriverNavigation $navigator, WebDriverDispatcher $dispatcher) + { + $this->navigator = $navigator; + $this->dispatcher = $dispatcher; + + return $this; + } + + /** + * @return WebDriverDispatcher + */ + public function getDispatcher() + { + return $this->dispatcher; + } + + /** + * @param mixed $method + */ + protected function dispatch($method) + { + if (!$this->dispatcher) { + return; + } + + $arguments = func_get_args(); + unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); + } + + /** + * @return WebDriverNavigation + */ + public function getNavigator() + { + return $this->navigator; } - $arguments = func_get_args(); - unset($arguments[0]); - $this->dispatcher->dispatch($method, $arguments); - } - - /** - * @return WebDriverNavigation - */ - public function getNavigator() { - return $this->navigator; - } - - /** - * @return $this - * @throws WebDriverException - */ - public function back() { - $this->dispatch( - 'beforeNavigateBack', - $this->getDispatcher()->getDefaultDriver() - ); - try { - $this->navigator->back(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + /** + * @throws WebDriverException + * @return $this + */ + public function back() + { + $this->dispatch( + 'beforeNavigateBack', + $this->getDispatcher()->getDefaultDriver() + ); + try { + $this->navigator->back(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch( + 'afterNavigateBack', + $this->getDispatcher()->getDefaultDriver() + ); + + return $this; } - $this->dispatch( - 'afterNavigateBack', - $this->getDispatcher()->getDefaultDriver() - ); - return $this; - } - - /** - * @return $this - * @throws WebDriverException - */ - public function forward() { - $this->dispatch( - 'beforeNavigateForward', - $this->getDispatcher()->getDefaultDriver() - ); - try { - $this->navigator->forward(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return $this + */ + public function forward() + { + $this->dispatch( + 'beforeNavigateForward', + $this->getDispatcher()->getDefaultDriver() + ); + try { + $this->navigator->forward(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch( + 'afterNavigateForward', + $this->getDispatcher()->getDefaultDriver() + ); + + return $this; } - $this->dispatch( - 'afterNavigateForward', - $this->getDispatcher()->getDefaultDriver() - ); - return $this; - } - - /** - * @return $this - * @throws WebDriverException - */ - public function refresh() { - try { - $this->navigator->refresh(); - return $this; - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return $this + */ + public function refresh() + { + try { + $this->navigator->refresh(); + + return $this; + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @param mixed $url - * @return $this - * @throws WebDriverException - */ - public function to($url) { - $this->dispatch( - 'beforeNavigateTo', - $url, - $this->getDispatcher()->getDefaultDriver() - ); - try { - $this->navigator->to($url); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param mixed $url + * @throws WebDriverException + * @return $this + */ + public function to($url) + { + $this->dispatch( + 'beforeNavigateTo', + $url, + $this->getDispatcher()->getDefaultDriver() + ); + try { + $this->navigator->to($url); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch( + 'afterNavigateTo', + $url, + $this->getDispatcher()->getDefaultDriver() + ); + + return $this; + } + + private function dispatchOnException($exception) + { + $this->dispatch('onException', $exception); + throw $exception; } - $this->dispatch( - 'afterNavigateTo', - $url, - $this->getDispatcher()->getDefaultDriver() - ); - return $this; - } - - private function dispatchOnException($exception) { - $this->dispatch('onException', $exception); - throw $exception; - } } diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index 3025bd8ba..8f6f20d81 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -24,346 +24,370 @@ use Facebook\WebDriver\WebDriverElement; use Facebook\WebDriver\WebDriverPoint; -class EventFiringWebElement implements WebDriverElement, WebDriverLocatable { - - /** - * @var WebDriverElement - */ - protected $element; - - /** - * @var WebDriverDispatcher - */ - protected $dispatcher; - - /** - * @param WebDriverElement $element - * @param WebDriverDispatcher $dispatcher - */ - public function __construct(WebDriverElement $element, - WebDriverDispatcher $dispatcher) { - $this->element = $element; - $this->dispatcher = $dispatcher; - return $this; - } - - /** - * @return WebDriverDispatcher - */ - public function getDispatcher() { - return $this->dispatcher; - } - - /** - * @param mixed $method - * @return void - */ - protected function dispatch($method) { - if (!$this->dispatcher) { - return; +class EventFiringWebElement implements WebDriverElement, WebDriverLocatable +{ + /** + * @var WebDriverElement + */ + protected $element; + /** + * @var WebDriverDispatcher + */ + protected $dispatcher; + + /** + * @param WebDriverElement $element + * @param WebDriverDispatcher $dispatcher + */ + public function __construct(WebDriverElement $element, WebDriverDispatcher $dispatcher) + { + $this->element = $element; + $this->dispatcher = $dispatcher; + + return $this; } - $arguments = func_get_args(); - unset($arguments[0]); - $this->dispatcher->dispatch($method, $arguments); - } - - /** - * @return WebDriverElement - */ - public function getElement() { - return $this->element; - } - - /** - * @param WebDriverElement $element - * @return EventFiringWebElement - */ - protected function newElement(WebDriverElement $element) { - return new static($element, $this->getDispatcher()); - } - - /** - * @param mixed $value - * @return $this - * @throws WebDriverException - */ - public function sendKeys($value) { - - $this->dispatch('beforeChangeValueOf', $this); - try { - $this->element->sendKeys($value); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @return WebDriverDispatcher + */ + public function getDispatcher() + { + return $this->dispatcher; } - $this->dispatch('afterChangeValueOf', $this); - return $this; - - } - - /** - * @return $this - * @throws WebDriverException - */ - public function click() { - $this->dispatch('beforeClickOn', $this); - try { - $this->element->click(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param mixed $method + */ + protected function dispatch($method) + { + if (!$this->dispatcher) { + return; + } + $arguments = func_get_args(); + unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); } - $this->dispatch('afterClickOn', $this); - return $this; - } - - /** - * @param WebDriverBy $by - * @return EventFiringWebElement - * @throws WebDriverException - */ - public function findElement(WebDriverBy $by) { - $this->dispatch( - 'beforeFindBy', - $by, - $this, - $this->dispatcher->getDefaultDriver()); - try { - $element = $this->newElement($this->element->findElement($by)); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @return WebDriverElement + */ + public function getElement() + { + return $this->element; } - $this->dispatch( - 'afterFindBy', - $by, - $this, - $this->dispatcher->getDefaultDriver() - ); - return $element; - } - - /** - * @param WebDriverBy $by - * @return array - * @throws WebDriverException - */ - public function findElements(WebDriverBy $by) { - $this->dispatch( - 'beforeFindBy', - $by, - $this, - $this->dispatcher->getDefaultDriver() - ); - try { - $elements = array(); - foreach ($this->element->findElements($by) as $element) { - $elements[] = $this->newElement($element); - } - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param WebDriverElement $element + * @return EventFiringWebElement + */ + protected function newElement(WebDriverElement $element) + { + return new static($element, $this->getDispatcher()); } - $this->dispatch( - 'afterFindBy', - $by, - $this, - $this->dispatcher->getDefaultDriver() - ); - return $elements; - } - - /** - * @return $this - * @throws WebDriverException - */ - public function clear() { - try { - $this->element->clear(); - return $this; - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param mixed $value + * @throws WebDriverException + * @return $this + */ + public function sendKeys($value) + { + $this->dispatch('beforeChangeValueOf', $this); + try { + $this->element->sendKeys($value); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterChangeValueOf', $this); + + return $this; } - } - - /** - * @param string $attribute_name - * @return string - * @throws WebDriverException - */ - public function getAttribute($attribute_name) { - try { - return $this->element->getAttribute($attribute_name); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return $this + */ + public function click() + { + $this->dispatch('beforeClickOn', $this); + try { + $this->element->click(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch('afterClickOn', $this); + + return $this; } - } - - /** - * @param string $css_property_name - * @return string - * @throws WebDriverException - */ - public function getCSSValue($css_property_name) { - try { - return $this->element->getCSSValue($css_property_name); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param WebDriverBy $by + * @throws WebDriverException + * @return EventFiringWebElement + */ + public function findElement(WebDriverBy $by) + { + $this->dispatch( + 'beforeFindBy', + $by, + $this, + $this->dispatcher->getDefaultDriver() + ); + try { + $element = $this->newElement($this->element->findElement($by)); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch( + 'afterFindBy', + $by, + $this, + $this->dispatcher->getDefaultDriver() + ); + + return $element; } - } - - /** - * @return WebDriverPoint - * @throws WebDriverException - */ - public function getLocation() { - try { - return $this->element->getLocation(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param WebDriverBy $by + * @throws WebDriverException + * @return array + */ + public function findElements(WebDriverBy $by) + { + $this->dispatch( + 'beforeFindBy', + $by, + $this, + $this->dispatcher->getDefaultDriver() + ); + try { + $elements = array(); + foreach ($this->element->findElements($by) as $element) { + $elements[] = $this->newElement($element); + } + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + $this->dispatch( + 'afterFindBy', + $by, + $this, + $this->dispatcher->getDefaultDriver() + ); + + return $elements; + } + + /** + * @throws WebDriverException + * @return $this + */ + public function clear() + { + try { + $this->element->clear(); + + return $this; + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return WebDriverPoint - * @throws WebDriverException - */ - public function getLocationOnScreenOnceScrolledIntoView() { - try { - return $this->element->getLocationOnScreenOnceScrolledIntoView(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @param string $attribute_name + * @throws WebDriverException + * @return string + */ + public function getAttribute($attribute_name) + { + try { + return $this->element->getAttribute($attribute_name); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + } + + /** + * @param string $css_property_name + * @throws WebDriverException + * @return string + */ + public function getCSSValue($css_property_name) + { + try { + return $this->element->getCSSValue($css_property_name); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return WebDriverCoordinates - */ - public function getCoordinates() { - try { - return $this->element->getCoordinates(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return WebDriverPoint + */ + public function getLocation() + { + try { + return $this->element->getLocation(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - - /** - * @return WebDriverDimension - * @throws WebDriverException - */ - public function getSize() { - try { - return $this->element->getSize(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return WebDriverPoint + */ + public function getLocationOnScreenOnceScrolledIntoView() + { + try { + return $this->element->getLocationOnScreenOnceScrolledIntoView(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getTagName() { - try { - return $this->element->getTagName(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @return WebDriverCoordinates + */ + public function getCoordinates() + { + try { + return $this->element->getCoordinates(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getText() { - try { - return $this->element->getText(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return WebDriverDimension + */ + public function getSize() + { + try { + return $this->element->getSize(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return bool - * @throws WebDriverException - */ - public function isDisplayed() { - try { - return $this->element->isDisplayed(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return string + */ + public function getTagName() + { + try { + return $this->element->getTagName(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return bool - * @throws WebDriverException - */ - public function isEnabled() { - try { - return $this->element->isEnabled(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return string + */ + public function getText() + { + try { + return $this->element->getText(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return bool - * @throws WebDriverException - */ - public function isSelected() { - try { - return $this->element->isSelected(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return bool + */ + public function isDisplayed() + { + try { + return $this->element->isDisplayed(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return $this - * @throws WebDriverException - */ - public function submit() { - try { - $this->element->submit(); - return $this; - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return bool + */ + public function isEnabled() + { + try { + return $this->element->isEnabled(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - /** - * @return string - * @throws WebDriverException - */ - public function getID() { - try { - return $this->element->getID(); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return bool + */ + public function isSelected() + { + try { + return $this->element->isSelected(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - - - /** - * Test if two element IDs refer to the same DOM element. - * - * @param WebDriverElement $other - * @return bool - */ - public function equals(WebDriverElement $other) { - try { - return $this->element->equals($other); - } catch (WebDriverException $exception) { - $this->dispatchOnException($exception); + + /** + * @throws WebDriverException + * @return $this + */ + public function submit() + { + try { + $this->element->submit(); + + return $this; + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } } - } - private function dispatchOnException($exception) { - $this->dispatch( - 'onException', - $exception, - $this->dispatcher->getDefaultDriver() - ); - throw $exception; - } + /** + * @throws WebDriverException + * @return string + */ + public function getID() + { + try { + return $this->element->getID(); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + } + /** + * Test if two element IDs refer to the same DOM element. + * + * @param WebDriverElement $other + * @return bool + */ + public function equals(WebDriverElement $other) + { + try { + return $this->element->equals($other); + } catch (WebDriverException $exception) { + $this->dispatchOnException($exception); + } + } + private function dispatchOnException($exception) + { + $this->dispatch( + 'onException', + $exception, + $this->dispatcher->getDefaultDriver() + ); + throw $exception; + } } diff --git a/lib/WebDriver.php b/lib/WebDriver.php index b143583ca..85e8c1931 100755 --- a/lib/WebDriver.php +++ b/lib/WebDriver.php @@ -18,119 +18,118 @@ /** * The interface for WebDriver. */ -interface WebDriver extends WebDriverSearchContext { - - /** - * Close the current window. - * - * @return WebDriver The current instance. - */ - public function close(); - - /** - * Load a new web page in the current browser window. - * - * @param string $url - * @return WebDriver The current instance. - */ - public function get($url); - - /** - * Get a string representing the current URL that the browser is looking at. - * - * @return string The current URL. - */ - public function getCurrentURL(); - - /** - * Get the source of the last loaded page. - * - * @return string The current page source. - */ - public function getPageSource(); - - /** - * Get the title of the current page. - * - * @return string The title of the current page. - */ - public function getTitle(); - - /** - * Return an opaque handle to this window that uniquely identifies it within - * this driver instance. - * - * @return string The current window handle. - */ - public function getWindowHandle(); - - /** - * Get all window handles available to the current session. - * - * @return array An array of string containing all available window handles. - */ - public function getWindowHandles(); - - /** - * Quits this driver, closing every associated window. - * - * @return void - */ - public function quit(); - - /** - * Take a screenshot of the current page. - * - * @param string $save_as The path of the screenshot to be saved. - * @return string The screenshot in PNG format. - */ - public function takeScreenshot($save_as = null); - - /** - * Construct a new WebDriverWait by the current WebDriver instance. - * Sample usage: - * - * $driver->wait(20, 1000)->until( - * WebDriverExpectedCondition::titleIs('WebDriver Page') - * ); - * - * @param int $timeout_in_second - * @param int $interval_in_millisecond - * @return WebDriverWait - */ - public function wait( - $timeout_in_second = 30, - $interval_in_millisecond = 250); - - /** - * An abstraction for managing stuff you would do in a browser menu. For - * example, adding and deleting cookies. - * - * @return WebDriverOptions - */ - public function manage(); - - /** - * An abstraction allowing the driver to access the browser's history and to - * navigate to a given URL. - * - * @return WebDriverNavigation - * @see WebDriverNavigation - */ - public function navigate(); - - /** - * Switch to a different window or frame. - * - * @return WebDriverTargetLocator - * @see WebDriverTargetLocator - */ - public function switchTo(); - - /** - * @param string $name - * @param array $params - * @return mixed - */ - public function execute($name, $params); +interface WebDriver extends WebDriverSearchContext +{ + /** + * Close the current window. + * + * @return WebDriver The current instance. + */ + public function close(); + + /** + * Load a new web page in the current browser window. + * + * @param string $url + * @return WebDriver The current instance. + */ + public function get($url); + + /** + * Get a string representing the current URL that the browser is looking at. + * + * @return string The current URL. + */ + public function getCurrentURL(); + + /** + * Get the source of the last loaded page. + * + * @return string The current page source. + */ + public function getPageSource(); + + /** + * Get the title of the current page. + * + * @return string The title of the current page. + */ + public function getTitle(); + + /** + * Return an opaque handle to this window that uniquely identifies it within + * this driver instance. + * + * @return string The current window handle. + */ + public function getWindowHandle(); + + /** + * Get all window handles available to the current session. + * + * @return array An array of string containing all available window handles. + */ + public function getWindowHandles(); + + /** + * Quits this driver, closing every associated window. + */ + public function quit(); + + /** + * Take a screenshot of the current page. + * + * @param string $save_as The path of the screenshot to be saved. + * @return string The screenshot in PNG format. + */ + public function takeScreenshot($save_as = null); + + /** + * Construct a new WebDriverWait by the current WebDriver instance. + * Sample usage: + * + * $driver->wait(20, 1000)->until( + * WebDriverExpectedCondition::titleIs('WebDriver Page') + * ); + * + * @param int $timeout_in_second + * @param int $interval_in_millisecond + * @return WebDriverWait + */ + public function wait( + $timeout_in_second = 30, + $interval_in_millisecond = 250 + ); + + /** + * An abstraction for managing stuff you would do in a browser menu. For + * example, adding and deleting cookies. + * + * @return WebDriverOptions + */ + public function manage(); + + /** + * An abstraction allowing the driver to access the browser's history and to + * navigate to a given URL. + * + * @return WebDriverNavigation + * @see WebDriverNavigation + */ + public function navigate(); + + /** + * Switch to a different window or frame. + * + * @return WebDriverTargetLocator + * @see WebDriverTargetLocator + */ + public function switchTo(); + + /** + * @param string $name + * @param array $params + * @return mixed + */ + public function execute($name, $params); } diff --git a/lib/WebDriverAction.php b/lib/WebDriverAction.php index a5d2d32d8..e73b883ad 100644 --- a/lib/WebDriverAction.php +++ b/lib/WebDriverAction.php @@ -18,10 +18,9 @@ /** * Interface representing a single user-interaction action. */ -interface WebDriverAction { - - /** - * @return void - */ - public function perform(); +interface WebDriverAction +{ + /** + */ + public function perform(); } diff --git a/lib/WebDriverAlert.php b/lib/WebDriverAlert.php index 8bef6d846..4ba9f6168 100644 --- a/lib/WebDriverAlert.php +++ b/lib/WebDriverAlert.php @@ -20,55 +20,62 @@ /** * An abstraction allowing the driver to manipulate the javascript alerts */ -class WebDriverAlert { +class WebDriverAlert +{ + protected $executor; - protected $executor; + public function __construct($executor) + { + $this->executor = $executor; + } - public function __construct($executor) { - $this->executor = $executor; - } + /** + * Accept alert + * + * @return WebDriverAlert The instance. + */ + public function accept() + { + $this->executor->execute(DriverCommand::ACCEPT_ALERT); - /** - * Accept alert - * - * @return WebDriverAlert The instance. - */ - public function accept() { - $this->executor->execute(DriverCommand::ACCEPT_ALERT); - return $this; - } + return $this; + } - /** - * Dismiss alert - * - * @return WebDriverAlert The instance. - */ - public function dismiss() { - $this->executor->execute(DriverCommand::DISMISS_ALERT); - return $this; - } + /** + * Dismiss alert + * + * @return WebDriverAlert The instance. + */ + public function dismiss() + { + $this->executor->execute(DriverCommand::DISMISS_ALERT); - /** - * Get alert text - * - * @return string - */ - public function getText() { - return $this->executor->execute(DriverCommand::GET_ALERT_TEXT); - } + return $this; + } - /** - * Send keystrokes to javascript prompt() dialog - * - * @param string $value - * @return WebDriverAlert - */ - public function sendKeys($value) { - $this->executor->execute( - DriverCommand::SET_ALERT_VALUE, - array('text' => $value) - ); - return $this; - } + /** + * Get alert text + * + * @return string + */ + public function getText() + { + return $this->executor->execute(DriverCommand::GET_ALERT_TEXT); + } + /** + * Send keystrokes to javascript prompt() dialog + * + * @param string $value + * @return WebDriverAlert + */ + public function sendKeys($value) + { + $this->executor->execute( + DriverCommand::SET_ALERT_VALUE, + array('text' => $value) + ); + + return $this; + } } diff --git a/lib/WebDriverBy.php b/lib/WebDriverBy.php index c409768a8..92242ae56 100644 --- a/lib/WebDriverBy.php +++ b/lib/WebDriverBy.php @@ -22,109 +22,120 @@ * * @see WebDriver::findElement, WebDriverElement::findElement */ -class WebDriverBy { +class WebDriverBy +{ + private $mechanism; + private $value; - private $mechanism; - private $value; + protected function __construct($mechanism, $value) + { + $this->mechanism = $mechanism; + $this->value = $value; + } - protected function __construct($mechanism, $value) { - $this->mechanism = $mechanism; - $this->value = $value; - } + /** + * @return string + */ + public function getMechanism() + { + return $this->mechanism; + } - /** - * @return string - */ - public function getMechanism() { - return $this->mechanism; - } + /** + * @return string + */ + public function getValue() + { + return $this->value; + } - /** - * @return string - */ - public function getValue() { - return $this->value; - } + /** + * Locates elements whose class name contains the search value; compound class + * names are not permitted. + * + * @param string $class_name + * @return WebDriverBy + */ + public static function className($class_name) + { + return new self('class name', $class_name); + } - /** - * Locates elements whose class name contains the search value; compound class - * names are not permitted. - * - * @param string $class_name - * @return WebDriverBy - */ - public static function className($class_name) { - return new WebDriverBy('class name', $class_name); - } + /** + * Locates elements matching a CSS selector. + * + * @param string $css_selector + * @return WebDriverBy + */ + public static function cssSelector($css_selector) + { + return new self('css selector', $css_selector); + } - /** - * Locates elements matching a CSS selector. - * - * @param string $css_selector - * @return WebDriverBy - */ - public static function cssSelector($css_selector) { - return new WebDriverBy('css selector', $css_selector); - } + /** + * Locates elements whose ID attribute matches the search value. + * + * @param string $id + * @return WebDriverBy + */ + public static function id($id) + { + return new self('id', $id); + } - /** - * Locates elements whose ID attribute matches the search value. - * - * @param string $id - * @return WebDriverBy - */ - public static function id($id) { - return new WebDriverBy('id', $id); - } + /** + * Locates elements whose NAME attribute matches the search value. + * + * @param string $name + * @return WebDriverBy + */ + public static function name($name) + { + return new self('name', $name); + } - /** - * Locates elements whose NAME attribute matches the search value. - * - * @param string $name - * @return WebDriverBy - */ - public static function name($name) { - return new WebDriverBy('name', $name); - } + /** + * Locates anchor elements whose visible text matches the search value. + * + * @param string $link_text + * @return WebDriverBy + */ + public static function linkText($link_text) + { + return new self('link text', $link_text); + } - /** - * Locates anchor elements whose visible text matches the search value. - * - * @param string $link_text - * @return WebDriverBy - */ - public static function linkText($link_text) { - return new WebDriverBy('link text', $link_text); - } + /** + * Locates anchor elements whose visible text partially matches the search + * value. + * + * @param string $partial_link_text + * @return WebDriverBy + */ + public static function partialLinkText($partial_link_text) + { + return new self('partial link text', $partial_link_text); + } - /** - * Locates anchor elements whose visible text partially matches the search - * value. - * - * @param string $partial_link_text - * @return WebDriverBy - */ - public static function partialLinkText($partial_link_text) { - return new WebDriverBy('partial link text', $partial_link_text); - } + /** + * Locates elements whose tag name matches the search value. + * + * @param string $tag_name + * @return WebDriverBy + */ + public static function tagName($tag_name) + { + return new self('tag name', $tag_name); + } - /** - * Locates elements whose tag name matches the search value. - * - * @param string $tag_name - * @return WebDriverBy - */ - public static function tagName($tag_name) { - return new WebDriverBy('tag name', $tag_name); - } - - /** - * Locates elements matching an XPath expression. - * - * @param string $xpath - * @return WebDriverBy - */ - public static function xpath($xpath) { - return new WebDriverBy('xpath', $xpath); - } + /** + * Locates elements matching an XPath expression. + * + * @param string $xpath + * @return WebDriverBy + */ + public static function xpath($xpath) + { + return new self('xpath', $xpath); + } } diff --git a/lib/WebDriverCapabilities.php b/lib/WebDriverCapabilities.php index 721db82e6..6fce03c08 100644 --- a/lib/WebDriverCapabilities.php +++ b/lib/WebDriverCapabilities.php @@ -15,37 +15,37 @@ namespace Facebook\WebDriver; -interface WebDriverCapabilities { - - /** - * @return string The name of the browser. - */ - public function getBrowserName(); - - /** - * @param string $name - * @return mixed The value of a capability. - */ - public function getCapability($name); - - /** - * @return string The name of the platform. - */ - public function getPlatform(); - - /** - * @return string The version of the browser. - */ - public function getVersion(); - - /** - * @param string $capability_name - * @return bool Whether the value is not null and not false. - */ - public function is($capability_name); - - /** - * @return bool Whether javascript is enabled. - */ - public function isJavascriptEnabled(); +interface WebDriverCapabilities +{ + /** + * @return string The name of the browser. + */ + public function getBrowserName(); + + /** + * @param string $name + * @return mixed The value of a capability. + */ + public function getCapability($name); + + /** + * @return string The name of the platform. + */ + public function getPlatform(); + + /** + * @return string The version of the browser. + */ + public function getVersion(); + + /** + * @param string $capability_name + * @return bool Whether the value is not null and not false. + */ + public function is($capability_name); + + /** + * @return bool Whether javascript is enabled. + */ + public function isJavascriptEnabled(); } diff --git a/lib/WebDriverCommandExecutor.php b/lib/WebDriverCommandExecutor.php index d58998f70..00357c6e7 100644 --- a/lib/WebDriverCommandExecutor.php +++ b/lib/WebDriverCommandExecutor.php @@ -20,12 +20,12 @@ /** * Interface for all command executor. */ -interface WebDriverCommandExecutor { - - /** - * @param WebDriverCommand $command - * - * @return mixed - */ - public function execute(WebDriverCommand $command); +interface WebDriverCommandExecutor +{ + /** + * @param WebDriverCommand $command + * + * @return mixed + */ + public function execute(WebDriverCommand $command); } diff --git a/lib/WebDriverDimension.php b/lib/WebDriverDimension.php index c66278931..5b274e29a 100644 --- a/lib/WebDriverDimension.php +++ b/lib/WebDriverDimension.php @@ -18,42 +18,46 @@ /** * Represent a dimension. */ -class WebDriverDimension { +class WebDriverDimension +{ + private $height; + private $width; - private $height, $width; + public function __construct($width, $height) + { + $this->width = $width; + $this->height = $height; + } - public function __construct($width, $height) { - $this->width = $width; - $this->height = $height; - } + /** + * Get the height. + * + * @return int The height. + */ + public function getHeight() + { + return $this->height; + } - /** - * Get the height. - * - * @return int The height. - */ - public function getHeight() { - return $this->height; - } + /** + * Get the width. + * + * @return int The width. + */ + public function getWidth() + { + return $this->width; + } - /** - * Get the width. - * - * @return int The width. - */ - public function getWidth() { - return $this->width; - } - - /** - * Check whether the given dimension is the same as the instance. - * - * @param WebDriverDimension $dimension The dimension to be compared with. - * @return bool Whether the height and the width are the same as the - * instance. - */ - public function equals(WebDriverDimension $dimension) { - return $this->height === $dimension->getHeight() && - $this->width === $dimension->getWidth(); - } + /** + * Check whether the given dimension is the same as the instance. + * + * @param WebDriverDimension $dimension The dimension to be compared with. + * @return bool Whether the height and the width are the same as the + * instance. + */ + public function equals(WebDriverDimension $dimension) + { + return $this->height === $dimension->getHeight() && $this->width === $dimension->getWidth(); + } } diff --git a/lib/WebDriverDispatcher.php b/lib/WebDriverDispatcher.php index c8caea4d9..202a3ec93 100644 --- a/lib/WebDriverDispatcher.php +++ b/lib/WebDriverDispatcher.php @@ -17,68 +17,75 @@ use Facebook\WebDriver\Support\Events\EventFiringWebDriver; -class WebDriverDispatcher { +class WebDriverDispatcher +{ + /** + * @var array + */ + protected $listeners = array(); + /** + * @var EventFiringWebDriver + */ + protected $driver = null; - /** - * @var array - */ - protected $listeners = array(); + /** + * this is needed so that EventFiringWebElement can pass the driver to the + * exception handling + * + * @param EventFiringWebDriver $driver + * @return $this + */ + public function setDefaultDriver(EventFiringWebDriver $driver) + { + $this->driver = $driver; - /** - * @var EventFiringWebDriver - */ - protected $driver = null; - - /** - * this is needed so that EventFiringWebElement can pass the driver to the - * exception handling - * - * @param EventFiringWebDriver $driver - * @return $this - */ - public function setDefaultDriver(EventFiringWebDriver $driver) { - $this->driver = $driver; - return $this; - } + return $this; + } - /** - * @return null|EventFiringWebDriver - */ - public function getDefaultDriver() { - return $this->driver; - } + /** + * @return null|EventFiringWebDriver + */ + public function getDefaultDriver() + { + return $this->driver; + } - /** - * @param WebDriverEventListener $listener - * @return $this - */ - public function register(WebDriverEventListener $listener) { - $this->listeners[] = $listener; - return $this; - } + /** + * @param WebDriverEventListener $listener + * @return $this + */ + public function register(WebDriverEventListener $listener) + { + $this->listeners[] = $listener; - /** - * @param WebDriverEventListener $listener - * @return $this - */ - public function unregister(WebDriverEventListener $listener) { - $key = array_search($listener, $this->listeners, true); - if ($key !== false) { - unset($this->listeners[$key]); + return $this; } - return $this; - } - /** - * @param mixed $method - * @param mixed $arguments - * @return $this - */ - public function dispatch($method, $arguments) { - foreach ($this->listeners as $listener) { - call_user_func_array(array($listener, $method), $arguments); + /** + * @param WebDriverEventListener $listener + * @return $this + */ + public function unregister(WebDriverEventListener $listener) + { + $key = array_search($listener, $this->listeners, true); + if ($key !== false) { + unset($this->listeners[$key]); + } + + return $this; } - return $this; - } + /** + * @param mixed $method + * @param mixed $arguments + * @return $this + */ + public function dispatch($method, $arguments) + { + foreach ($this->listeners as $listener) { + call_user_func_array(array($listener, $method), $arguments); + } + + return $this; + } } diff --git a/lib/WebDriverElement.php b/lib/WebDriverElement.php index d49190604..6eb7df5c6 100644 --- a/lib/WebDriverElement.php +++ b/lib/WebDriverElement.php @@ -18,119 +18,119 @@ /** * Interface for an HTML element in the WebDriver framework. */ -interface WebDriverElement extends WebDriverSearchContext { - - /** - * If this element is a TEXTAREA or text INPUT element, this will clear the - * value. - * - * @return WebDriverElement The current instance. - */ - public function clear(); - - /** - * Click this element. - * - * @return WebDriverElement The current instance. - */ - public function click(); - - /** - * Get the value of a the given attribute of the element. - * - * @param string $attribute_name The name of the attribute. - * @return string The value of the attribute. - */ - public function getAttribute($attribute_name); - - /** - * Get the value of a given CSS property. - * - * @param string $css_property_name The name of the CSS property. - * @return string The value of the CSS property. - */ - public function getCSSValue($css_property_name); - - /** - * Get the location of element relative to the top-left corner of the page. - * - * @return WebDriverPoint The location of the element. - */ - public function getLocation(); - - /** - * Try scrolling the element into the view port and return the location of - * element relative to the top-left corner of the page afterwards. - * - * @return WebDriverPoint The location of the element. - */ - public function getLocationOnScreenOnceScrolledIntoView(); - - /** - * Get the size of element. - * - * @return WebDriverDimension The dimension of the element. - */ - public function getSize(); - - /** - * Get the tag name of this element. - * - * @return string The tag name. - */ - public function getTagName(); - - /** - * Get the visible (i.e. not hidden by CSS) innerText of this element, - * including sub-elements, without any leading or trailing whitespace. - * - * @return string The visible innerText of this element. - */ - public function getText(); - - /** - * Is this element displayed or not? This method avoids the problem of having - * to parse an element's "style" attribute. - * - * @return bool - */ - public function isDisplayed(); - - /** - * Is the element currently enabled or not? This will generally return true - * for everything but disabled input elements. - * - * @return bool - */ - public function isEnabled(); - - /** - * Determine whether or not this element is selected or not. - * - * @return bool - */ - public function isSelected(); - - /** - * Simulate typing into an element, which may set its value. - * - * @param mixed $value The data to be typed. - * @return WebDriverElement The current instance. - */ - public function sendKeys($value); - - /** - * If this current element is a form, or an element within a form, then this - * will be submitted to the remote server. - * - * @return WebDriverElement The current instance. - */ - public function submit(); - - /** - * Get the opaque ID of the element. - * - * @return string The opaque ID. - */ - public function getID(); +interface WebDriverElement extends WebDriverSearchContext +{ + /** + * If this element is a TEXTAREA or text INPUT element, this will clear the + * value. + * + * @return WebDriverElement The current instance. + */ + public function clear(); + + /** + * Click this element. + * + * @return WebDriverElement The current instance. + */ + public function click(); + + /** + * Get the value of a the given attribute of the element. + * + * @param string $attribute_name The name of the attribute. + * @return string The value of the attribute. + */ + public function getAttribute($attribute_name); + + /** + * Get the value of a given CSS property. + * + * @param string $css_property_name The name of the CSS property. + * @return string The value of the CSS property. + */ + public function getCSSValue($css_property_name); + + /** + * Get the location of element relative to the top-left corner of the page. + * + * @return WebDriverPoint The location of the element. + */ + public function getLocation(); + + /** + * Try scrolling the element into the view port and return the location of + * element relative to the top-left corner of the page afterwards. + * + * @return WebDriverPoint The location of the element. + */ + public function getLocationOnScreenOnceScrolledIntoView(); + + /** + * Get the size of element. + * + * @return WebDriverDimension The dimension of the element. + */ + public function getSize(); + + /** + * Get the tag name of this element. + * + * @return string The tag name. + */ + public function getTagName(); + + /** + * Get the visible (i.e. not hidden by CSS) innerText of this element, + * including sub-elements, without any leading or trailing whitespace. + * + * @return string The visible innerText of this element. + */ + public function getText(); + + /** + * Is this element displayed or not? This method avoids the problem of having + * to parse an element's "style" attribute. + * + * @return bool + */ + public function isDisplayed(); + + /** + * Is the element currently enabled or not? This will generally return true + * for everything but disabled input elements. + * + * @return bool + */ + public function isEnabled(); + + /** + * Determine whether or not this element is selected or not. + * + * @return bool + */ + public function isSelected(); + + /** + * Simulate typing into an element, which may set its value. + * + * @param mixed $value The data to be typed. + * @return WebDriverElement The current instance. + */ + public function sendKeys($value); + + /** + * If this current element is a form, or an element within a form, then this + * will be submitted to the remote server. + * + * @return WebDriverElement The current instance. + */ + public function submit(); + + /** + * Get the opaque ID of the element. + * + * @return string The opaque ID. + */ + public function getID(); } diff --git a/lib/WebDriverEventListener.php b/lib/WebDriverEventListener.php index afea9c0fd..074adebf6 100644 --- a/lib/WebDriverEventListener.php +++ b/lib/WebDriverEventListener.php @@ -19,110 +19,89 @@ use Facebook\WebDriver\Support\Events\EventFiringWebDriver; use Facebook\WebDriver\Support\Events\EventFiringWebElement; -interface WebDriverEventListener { - - /** - * @param string $url - * @param EventFiringWebDriver $driver - * @return void - */ - public function beforeNavigateTo($url, EventFiringWebDriver $driver); - - /** - * @param string $url - * @param EventFiringWebDriver $driver - * @return void - */ - public function afterNavigateTo($url, EventFiringWebDriver $driver); - - /** - * @param EventFiringWebDriver $driver - * @return void - */ - public function beforeNavigateBack(EventFiringWebDriver $driver); - - /** - * @param EventFiringWebDriver $driver - * @return void - */ - public function afterNavigateBack(EventFiringWebDriver $driver); - - /** - * @param EventFiringWebDriver $driver - * @return void - */ - public function beforeNavigateForward(EventFiringWebDriver $driver); - - /** - * @param EventFiringWebDriver $driver - * @return void - */ - public function afterNavigateForward(EventFiringWebDriver $driver); - - /** - * @param WebDriverBy $by - * @param EventFiringWebElement|null $element - * @param EventFiringWebDriver $driver - * @return void - */ - public function beforeFindBy(WebDriverBy $by, - $element, - EventFiringWebDriver $driver); - - /** - * @param WebDriverBy $by - * @param EventFiringWebElement|null $element - * @param EventFiringWebDriver $driver - * @return void - */ - public function afterFindBy(WebDriverBy $by, - $element, - EventFiringWebDriver $driver); - - /** - * @param string $script - * @param EventFiringWebDriver $driver - * @return void - */ - public function beforeScript($script, EventFiringWebDriver $driver); - - /** - * @param string $script - * @param EventFiringWebDriver $driver - * @return void - */ - public function afterScript($script, EventFiringWebDriver $driver); - - /** - * @param EventFiringWebElement $element - * @return void - */ - public function beforeClickOn(EventFiringWebElement $element); - - /** - * @param EventFiringWebElement $element - * @return void - */ - public function afterClickOn(EventFiringWebElement $element); - - /** - * @param EventFiringWebElement $element - * @return void - */ - public function beforeChangeValueOf(EventFiringWebElement $element); - - /** - * @param EventFiringWebElement $element - * @return void - */ - public function afterChangeValueOf(EventFiringWebElement $element); - - /** - * @param WebDriverException $exception - * @param EventFiringWebDriver $driver - * @return void - */ - public function onException(WebDriverException $exception, - EventFiringWebDriver $driver = null); - +interface WebDriverEventListener +{ + /** + * @param string $url + * @param EventFiringWebDriver $driver + */ + public function beforeNavigateTo($url, EventFiringWebDriver $driver); + + /** + * @param string $url + * @param EventFiringWebDriver $driver + */ + public function afterNavigateTo($url, EventFiringWebDriver $driver); + + /** + * @param EventFiringWebDriver $driver + */ + public function beforeNavigateBack(EventFiringWebDriver $driver); + + /** + * @param EventFiringWebDriver $driver + */ + public function afterNavigateBack(EventFiringWebDriver $driver); + + /** + * @param EventFiringWebDriver $driver + */ + public function beforeNavigateForward(EventFiringWebDriver $driver); + + /** + * @param EventFiringWebDriver $driver + */ + public function afterNavigateForward(EventFiringWebDriver $driver); + + /** + * @param WebDriverBy $by + * @param EventFiringWebElement|null $element + * @param EventFiringWebDriver $driver + */ + public function beforeFindBy(WebDriverBy $by, $element, EventFiringWebDriver $driver); + + /** + * @param WebDriverBy $by + * @param EventFiringWebElement|null $element + * @param EventFiringWebDriver $driver + */ + public function afterFindBy(WebDriverBy $by, $element, EventFiringWebDriver $driver); + + /** + * @param string $script + * @param EventFiringWebDriver $driver + */ + public function beforeScript($script, EventFiringWebDriver $driver); + + /** + * @param string $script + * @param EventFiringWebDriver $driver + */ + public function afterScript($script, EventFiringWebDriver $driver); + + /** + * @param EventFiringWebElement $element + */ + public function beforeClickOn(EventFiringWebElement $element); + + /** + * @param EventFiringWebElement $element + */ + public function afterClickOn(EventFiringWebElement $element); + + /** + * @param EventFiringWebElement $element + */ + public function beforeChangeValueOf(EventFiringWebElement $element); + + /** + * @param EventFiringWebElement $element + */ + public function afterChangeValueOf(EventFiringWebElement $element); + + /** + * @param WebDriverException $exception + * @param EventFiringWebDriver $driver + */ + public function onException(WebDriverException $exception, EventFiringWebDriver $driver = null); } diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 3de9a9731..8c069bd41 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -15,402 +15,427 @@ namespace Facebook\WebDriver; -use Facebook\WebDriver\Exception\StaleElementReferenceException; -use Facebook\WebDriver\Exception\NoSuchFrameException; -use Facebook\WebDriver\Exception\NoSuchElementException; use Facebook\WebDriver\Exception\NoAlertOpenException; +use Facebook\WebDriver\Exception\NoSuchElementException; +use Facebook\WebDriver\Exception\NoSuchFrameException; +use Facebook\WebDriver\Exception\StaleElementReferenceException; /** * Canned ExpectedConditions which are generally useful within webdriver tests. * * @see WebDriverWait */ -class WebDriverExpectedCondition { - - /** - * A closure function to be executed by WebDriverWait. It should return - * a truthy value, mostly boolean or a WebDriverElement, on success. - */ - private $apply; - - /** - * @return (function():T) a closure function to be executed by WebDriverWait - */ - public function getApply() { - return $this->apply; - } - - protected function __construct($apply) { - $this->apply = $apply; - } - - /** - * An expectation for checking the title of a page. - * - * @param string $title The expected title, which must be an exact match. - * @return bool WebDriverExpectedCondition True when the title matches, - * false otherwise. - */ - public static function titleIs($title) { - return new WebDriverExpectedCondition( - function ($driver) use ($title) { - return $title === $driver->getTitle(); - } - ); - } - - /** - * An expectation for checking substring of a page Title. - * - * @param string $title The expected substring of Title. - * @return bool WebDriverExpectedCondition True when in title, - * false otherwise. - */ - public static function titleContains($title) { - return new WebDriverExpectedCondition( - function ($driver) use ($title) { - return strpos($driver->getTitle(), $title) !== false; - } - ); - } - - /** - * An expectation for checking that an element is present on the DOM of a - * page. This does not necessarily mean that the element is visible. - * - * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition The element which - * is located. - */ - public static function presenceOfElementLocated(WebDriverBy $by) { - return new WebDriverExpectedCondition( - function ($driver) use ($by) { - return $driver->findElement($by); - } - ); - } - - /** - * An expectation for checking that an element is present on the DOM of a page - * and visible. Visibility means that the element is not only displayed but - * also has a height and width that is greater than 0. - * - * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition The element which is - * located and visible. - */ - public static function visibilityOfElementLocated(WebDriverBy $by) { - return new WebDriverExpectedCondition( - function ($driver) use ($by) { - try { - $element = $driver->findElement($by); - return $element->isDisplayed() ? $element : null; - } catch (StaleElementReferenceException $e) { - return null; - } - } - ); - } - - /** - * An expectation for checking that an element, known to be present on the DOM - * of a page, is visible. Visibility means that the element is not only - * displayed but also has a height and width that is greater than 0. - * - * @param WebDriverElement $element The element to be checked. - * @return WebDriverExpectedCondition The same - * WebDriverElement once it is visible. - */ - public static function visibilityOf(WebDriverElement $element) { - return new WebDriverExpectedCondition( - function ($driver) use ($element) { - return $element->isDisplayed() ? $element : null; - } - ); - } - - /** - * An expectation for checking that there is at least one element present on a - * web page. - * - * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition An array of WebDriverElements - * once they are located. - */ - public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) { - return new WebDriverExpectedCondition( - function ($driver) use ($by) { - $elements = $driver->findElements($by); - return count($elements) > 0 ? $elements : null; - } - ); - } - - /** - * An expectation for checking if the given text is present in the specified - * element. - * - * @param WebDriverBy $by The locator used to find the element. - * @param string $text The text to be presented in the element. - * @return bool WebDriverExpectedCondition Whether the text is presented. - */ - public static function textToBePresentInElement( - WebDriverBy $by, $text) { - return new WebDriverExpectedCondition( - function ($driver) use ($by, $text) { - try { - $element_text = $driver->findElement($by)->getText(); - return strpos($element_text, $text) !== false; - } catch (StaleElementReferenceException $e) { - return null; - } - } - ); - } - - /** - * An expectation for checking if the given text is present in the specified - * elements value attribute. - * - * @param WebDriverBy $by The locator used to find the element. - * @param string $text The text to be presented in the element value. - * @return bool WebDriverExpectedCondition Whether the text is presented. - */ - public static function textToBePresentInElementValue( - WebDriverBy $by, $text) { - return new WebDriverExpectedCondition( - function ($driver) use ($by, $text) { - try { - $element_text = $driver->findElement($by)->getAttribute('value'); - return strpos($element_text, $text) !== false; - } catch (StaleElementReferenceException $e) { - return null; - } - } - ); - } - - /** - * Expectation for checking if iFrame exists. - * If iFrame exists switches driver's focus to the iFrame - * - * @param string $frame_locator The locator used to find the iFrame - * expected to be either the id or name value of the i/frame - * @return WebDriverExpectedCondition object focused on new frame - * when frame is found bool false otherwise - */ - public static function frameToBeAvailableAndSwitchToIt($frame_locator) { - return new WebDriverExpectedCondition( - function ($driver) use ($frame_locator) { - try { - return $driver->switchTo()->frame($frame_locator); - } catch (NoSuchFrameException $e) { - return false; - } - } - ); - } - - /** - * An expectation for checking that an element is either invisible or not - * present on the DOM. - * - * @param WebDriverBy $by The locator used to find the element. - * @return bool WebDriverExpectedCondition Whether there is no element - * located. - */ - public static function invisibilityOfElementLocated(WebDriverBy $by) { - return new WebDriverExpectedCondition( - function ($driver) use ($by) { - try { - return !($driver->findElement($by)->isDisplayed()); - } catch (NoSuchElementException $e) { - return true; - } catch (StaleElementReferenceException $e) { - return true; - } - } - ); - } - - /** - * An expectation for checking that an element with text is either invisible - * or not present on the DOM. - * - * @param WebdriverBy $by The locator used to find the element. - * @param string $text The text of the element. - * @return bool WebDriverExpectedCondition Whether the text is found in the - * element located. - */ - public static function invisibilityOfElementWithText( - WebDriverBy $by, $text) { - return new WebDriverExpectedCondition( - function ($driver) use ($by, $text) { - try { - return !($driver->findElement($by)->getText() === $text); - } catch (NoSuchElementException $e) { - return true; - } catch (StaleElementReferenceException $e) { - return true; - } - } - ); - } - - /** - * An expectation for checking an element is visible and enabled such that you - * can click it. - * - * @param WebDriverBy $by The locator used to find the element - * @return WebDriverExpectedCondition The WebDriverElement - * once it is located, visible and clickable - */ - public static function elementToBeClickable(WebDriverBy $by) { - $visibility_of_element_located = - WebDriverExpectedCondition::visibilityOfElementLocated($by); - return new WebDriverExpectedCondition( - function ($driver) use ($visibility_of_element_located) { - $element = call_user_func( - $visibility_of_element_located->getApply(), - $driver +class WebDriverExpectedCondition +{ + /** + * A closure function to be executed by WebDriverWait. It should return + * a truthy value, mostly boolean or a WebDriverElement, on success. + */ + private $apply; + + /** + * @return (function():T) a closure function to be executed by WebDriverWait + */ + public function getApply() + { + return $this->apply; + } + + protected function __construct($apply) + { + $this->apply = $apply; + } + + /** + * An expectation for checking the title of a page. + * + * @param string $title The expected title, which must be an exact match. + * @return bool WebDriverExpectedCondition True when the title matches, + * false otherwise. + */ + public static function titleIs($title) + { + return new self( + function ($driver) use ($title) { + return $title === $driver->getTitle(); + } + ); + } + + /** + * An expectation for checking substring of a page Title. + * + * @param string $title The expected substring of Title. + * @return bool WebDriverExpectedCondition True when in title, + * false otherwise. + */ + public static function titleContains($title) + { + return new self( + function ($driver) use ($title) { + return strpos($driver->getTitle(), $title) !== false; + } + ); + } + + /** + * An expectation for checking that an element is present on the DOM of a + * page. This does not necessarily mean that the element is visible. + * + * @param WebDriverBy $by The locator used to find the element. + * @return WebDriverExpectedCondition The element which + * is located. + */ + public static function presenceOfElementLocated(WebDriverBy $by) + { + return new self( + function ($driver) use ($by) { + return $driver->findElement($by); + } + ); + } + + /** + * An expectation for checking that an element is present on the DOM of a page + * and visible. Visibility means that the element is not only displayed but + * also has a height and width that is greater than 0. + * + * @param WebDriverBy $by The locator used to find the element. + * @return WebDriverExpectedCondition The element which is + * located and visible. + */ + public static function visibilityOfElementLocated(WebDriverBy $by) + { + return new self( + function ($driver) use ($by) { + try { + $element = $driver->findElement($by); + + return $element->isDisplayed() ? $element : null; + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + + /** + * An expectation for checking that an element, known to be present on the DOM + * of a page, is visible. Visibility means that the element is not only + * displayed but also has a height and width that is greater than 0. + * + * @param WebDriverElement $element The element to be checked. + * @return WebDriverExpectedCondition The same + * WebDriverElement once it is visible. + */ + public static function visibilityOf(WebDriverElement $element) + { + return new self( + function ($driver) use ($element) { + return $element->isDisplayed() ? $element : null; + } + ); + } + + /** + * An expectation for checking that there is at least one element present on a + * web page. + * + * @param WebDriverBy $by The locator used to find the element. + * @return WebDriverExpectedCondition An array of WebDriverElements + * once they are located. + */ + public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) + { + return new self( + function ($driver) use ($by) { + $elements = $driver->findElements($by); + + return count($elements) > 0 ? $elements : null; + } ); - try { - if ($element !== null && $element->isEnabled()) { - return $element; - } else { - return null; - } - } catch (StaleElementReferenceException $e) { - return null; - } - } - ); - } - - /** - * Wait until an element is no longer attached to the DOM. - * - * @param WebDriverElement $element The element to wait for. - * @return bool WebDriverExpectedCondition false if the element is still - * attached to the DOM, true otherwise. - */ - public static function stalenessOf(WebDriverElement $element) { - return new WebDriverExpectedCondition( - function ($driver) use ($element) { - try { - $element->isEnabled(); - return false; - } catch (StaleElementReferenceException $e) { - return true; - } - } - ); - } - - /** - * Wrapper for a condition, which allows for elements to update by redrawing. - * - * This works around the problem of conditions which have two parts: find an - * element and then check for some condition on it. For these conditions it is - * possible that an element is located and then subsequently it is redrawn on - * the client. When this happens a StaleElementReferenceException is thrown - * when the second part of the condition is checked. - * - * @param WebDriverExpectedCondition $condition The condition wrapped. - * @return WebDriverExpectedCondition The return value of the - * getApply() of the given condition. - */ - public static function refreshed(WebDriverExpectedCondition $condition) { - return new WebDriverExpectedCondition( - function ($driver) use ($condition) { - try { - return call_user_func($condition->getApply(), $driver); - } catch (StaleElementReferenceException $e) { - return null; - } - } - ); - } - - /** - * An expectation for checking if the given element is selected. - * - * @param mixed $element_or_by Either the element or the locator. - * @return bool WebDriverExpectedCondition whether the element is selected. - */ - public static function elementToBeSelected($element_or_by) { - return WebDriverExpectedCondition::elementSelectionStateToBe( - $element_or_by, - true - ); - } - - /** - * An expectation for checking if the given element is selected. - * - * @param mixed $element_or_by Either the element or the locator. - * @param bool $selected The required state. - * @return bool WebDriverExpectedCondition Whether the element is selected. - */ - public static function elementSelectionStateToBe( - $element_or_by, - $selected - ) { - if ($element_or_by instanceof WebDriverElement) { - return new WebDriverExpectedCondition( - function ($driver) use ($element_or_by, $selected) { - return $element_or_by->isSelected() === $selected; - } - ); - } else if ($element_or_by instanceof WebDriverBy) { - return new WebDriverExpectedCondition( - function ($driver) use ($element_or_by, $selected) { - try { - $element = $driver->findElement($element_or_by); - return $element->isSelected() === $selected; - } catch (StaleElementReferenceException $e) { - return null; - } - } - ); } - } - - /** - * An expectation for whether an alert() box is present. - * - * @return WebDriverExpectedCondition if alert() is present, - * null otherwise. - */ - public static function alertIsPresent() { - return new WebDriverExpectedCondition( - function ($driver) { - try { - // Unlike the Java code, we get a WebDriverAlert object regardless - // of whether there is an alert. Calling getText() will throw - // an exception if it is not really there. - $alert = $driver->switchTo()->alert(); - $alert->getText(); - return $alert; - } catch (NoAlertOpenException $e) { - return null; + + /** + * An expectation for checking if the given text is present in the specified + * element. + * + * @param WebDriverBy $by The locator used to find the element. + * @param string $text The text to be presented in the element. + * @return bool WebDriverExpectedCondition Whether the text is presented. + */ + public static function textToBePresentInElement(WebDriverBy $by, $text) + { + return new self( + function ($driver) use ($by, $text) { + try { + $element_text = $driver->findElement($by)->getText(); + + return strpos($element_text, $text) !== false; + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + + /** + * An expectation for checking if the given text is present in the specified + * elements value attribute. + * + * @param WebDriverBy $by The locator used to find the element. + * @param string $text The text to be presented in the element value. + * @return bool WebDriverExpectedCondition Whether the text is presented. + */ + public static function textToBePresentInElementValue(WebDriverBy $by, $text) + { + return new self( + function ($driver) use ($by, $text) { + try { + $element_text = $driver->findElement($by)->getAttribute('value'); + + return strpos($element_text, $text) !== false; + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + + /** + * Expectation for checking if iFrame exists. + * If iFrame exists switches driver's focus to the iFrame + * + * @param string $frame_locator The locator used to find the iFrame + * expected to be either the id or name value of the i/frame + * @return WebDriverExpectedCondition object focused on new frame + * when frame is found bool false otherwise + */ + public static function frameToBeAvailableAndSwitchToIt($frame_locator) + { + return new self( + function ($driver) use ($frame_locator) { + try { + return $driver->switchTo()->frame($frame_locator); + } catch (NoSuchFrameException $e) { + return false; + } + } + ); + } + + /** + * An expectation for checking that an element is either invisible or not + * present on the DOM. + * + * @param WebDriverBy $by The locator used to find the element. + * @return bool WebDriverExpectedCondition Whether there is no element + * located. + */ + public static function invisibilityOfElementLocated(WebDriverBy $by) + { + return new self( + function ($driver) use ($by) { + try { + return !($driver->findElement($by)->isDisplayed()); + } catch (NoSuchElementException $e) { + return true; + } catch (StaleElementReferenceException $e) { + return true; + } + } + ); + } + + /** + * An expectation for checking that an element with text is either invisible + * or not present on the DOM. + * + * @param WebdriverBy $by The locator used to find the element. + * @param string $text The text of the element. + * @return bool WebDriverExpectedCondition Whether the text is found in the + * element located. + */ + public static function invisibilityOfElementWithText(WebDriverBy $by, $text) + { + return new self( + function ($driver) use ($by, $text) { + try { + return !($driver->findElement($by)->getText() === $text); + } catch (NoSuchElementException $e) { + return true; + } catch (StaleElementReferenceException $e) { + return true; + } + } + ); + } + + /** + * An expectation for checking an element is visible and enabled such that you + * can click it. + * + * @param WebDriverBy $by The locator used to find the element + * @return WebDriverExpectedCondition The WebDriverElement + * once it is located, visible and clickable + */ + public static function elementToBeClickable(WebDriverBy $by) + { + $visibility_of_element_located = + self::visibilityOfElementLocated($by); + + return new self( + function ($driver) use ($visibility_of_element_located) { + $element = call_user_func( + $visibility_of_element_located->getApply(), + $driver + ); + try { + if ($element !== null && $element->isEnabled()) { + return $element; + } else { + return null; + } + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + + /** + * Wait until an element is no longer attached to the DOM. + * + * @param WebDriverElement $element The element to wait for. + * @return bool WebDriverExpectedCondition false if the element is still + * attached to the DOM, true otherwise. + */ + public static function stalenessOf(WebDriverElement $element) + { + return new self( + function ($driver) use ($element) { + try { + $element->isEnabled(); + + return false; + } catch (StaleElementReferenceException $e) { + return true; + } + } + ); + } + + /** + * Wrapper for a condition, which allows for elements to update by redrawing. + * + * This works around the problem of conditions which have two parts: find an + * element and then check for some condition on it. For these conditions it is + * possible that an element is located and then subsequently it is redrawn on + * the client. When this happens a StaleElementReferenceException is thrown + * when the second part of the condition is checked. + * + * @param WebDriverExpectedCondition $condition The condition wrapped. + * @return WebDriverExpectedCondition The return value of the + * getApply() of the given condition. + */ + public static function refreshed(WebDriverExpectedCondition $condition) + { + return new self( + function ($driver) use ($condition) { + try { + return call_user_func($condition->getApply(), $driver); + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + + /** + * An expectation for checking if the given element is selected. + * + * @param mixed $element_or_by Either the element or the locator. + * @return bool WebDriverExpectedCondition whether the element is selected. + */ + public static function elementToBeSelected($element_or_by) + { + return self::elementSelectionStateToBe( + $element_or_by, + true + ); + } + + /** + * An expectation for checking if the given element is selected. + * + * @param mixed $element_or_by Either the element or the locator. + * @param bool $selected The required state. + * @return bool WebDriverExpectedCondition Whether the element is selected. + */ + public static function elementSelectionStateToBe($element_or_by, $selected) + { + if ($element_or_by instanceof WebDriverElement) { + return new self( + function ($driver) use ($element_or_by, $selected) { + return $element_or_by->isSelected() === $selected; + } + ); + } else { + if ($element_or_by instanceof WebDriverBy) { + return new self( + function ($driver) use ($element_or_by, $selected) { + try { + $element = $driver->findElement($element_or_by); + + return $element->isSelected() === $selected; + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } } - } - ); - } - - /** - * An expectation with the logical opposite condition of the given condition. - * - * @param WebDriverExpectedCondition $condition The condition to be negated. - * @return mixed The negation of the result of the given condition. - */ - public static function not(WebDriverExpectedCondition $condition) { - return new WebDriverExpectedCondition( - function ($driver) use ($condition) { - $result = call_user_func($condition->getApply(), $driver); - return !$result; - } - ); - } + } + + /** + * An expectation for whether an alert() box is present. + * + * @return WebDriverExpectedCondition if alert() is present, + * null otherwise. + */ + public static function alertIsPresent() + { + return new self( + function ($driver) { + try { + // Unlike the Java code, we get a WebDriverAlert object regardless + // of whether there is an alert. Calling getText() will throw + // an exception if it is not really there. + $alert = $driver->switchTo()->alert(); + $alert->getText(); + + return $alert; + } catch (NoAlertOpenException $e) { + return null; + } + } + ); + } + + /** + * An expectation with the logical opposite condition of the given condition. + * + * @param WebDriverExpectedCondition $condition The condition to be negated. + * @return mixed The negation of the result of the given condition. + */ + public static function not(WebDriverExpectedCondition $condition) + { + return new self( + function ($driver) use ($condition) { + $result = call_user_func($condition->getApply(), $driver); + + return !$result; + } + ); + } } diff --git a/lib/WebDriverHasInputDevices.php b/lib/WebDriverHasInputDevices.php index 76c82dddc..93e42a30a 100644 --- a/lib/WebDriverHasInputDevices.php +++ b/lib/WebDriverHasInputDevices.php @@ -18,15 +18,15 @@ /** * Interface implemented by each driver that allows access to the input devices. */ -interface WebDriverHasInputDevices { +interface WebDriverHasInputDevices +{ + /** + * @return WebDriverKeyBoard + */ + public function getKeyboard(); - /** - * @return WebDriverKeyBoard - */ - public function getKeyboard(); - - /** - * @return WebDriverMouse - */ - public function getMouse(); + /** + * @return WebDriverMouse + */ + public function getMouse(); } diff --git a/lib/WebDriverKeyboard.php b/lib/WebDriverKeyboard.php index 042e47108..f44582a12 100644 --- a/lib/WebDriverKeyboard.php +++ b/lib/WebDriverKeyboard.php @@ -15,31 +15,31 @@ namespace Facebook\WebDriver; -interface WebDriverKeyboard { +interface WebDriverKeyboard +{ + /** + * Send a sequence of keys. + * + * @param string $keys + * @return $this + */ + public function sendKeys($keys); - /** - * Send a sequence of keys. - * - * @param string $keys - * @return $this - */ - public function sendKeys($keys); + /** + * Press a key + * + * @see WebDriverKeys + * @param string $key + * @return $this + */ + public function pressKey($key); - /** - * Press a key - * - * @see WebDriverKeys - * @param string $key - * @return $this - */ - public function pressKey($key); - - /** - * Release a key - * - * @see WebDriverKeys - * @param string $key - * @return $this - */ - public function releaseKey($key); + /** + * Release a key + * + * @see WebDriverKeys + * @param string $key + * @return $this + */ + public function releaseKey($key); } diff --git a/lib/WebDriverKeys.php b/lib/WebDriverKeys.php index b946cec9f..ecab819b6 100644 --- a/lib/WebDriverKeys.php +++ b/lib/WebDriverKeys.php @@ -19,97 +19,97 @@ * Representations of pressable keys that aren't text. * These are stored in the Unicode PUA (Private Use Area) code points. */ -class WebDriverKeys { +class WebDriverKeys +{ + const NULL = "\xEE\x80\x80"; + const CANCEL = "\xEE\x80\x81"; + const HELP = "\xEE\x80\x82"; + const BACKSPACE = "\xEE\x80\x83"; + const TAB = "\xEE\x80\x84"; + const CLEAR = "\xEE\x80\x85"; + const RETURN_KEY = "\xEE\x80\x86"; // php does not allow RETURN + const ENTER = "\xEE\x80\x87"; + const SHIFT = "\xEE\x80\x88"; + const LEFT_SHIFT = "\xEE\x80\x88"; + const CONTROL = "\xEE\x80\x89"; + const LEFT_CONTROL = "\xEE\x80\x89"; + const ALT = "\xEE\x80\x8A"; + const LEFT_ALT = "\xEE\x80\x8A"; + const PAUSE = "\xEE\x80\x8B"; + const ESCAPE = "\xEE\x80\x8C"; + const SPACE = "\xEE\x80\x8D"; + const PAGE_UP = "\xEE\x80\x8E"; + const PAGE_DOWN = "\xEE\x80\x8F"; + const END = "\xEE\x80\x90"; + const HOME = "\xEE\x80\x91"; + const LEFT = "\xEE\x80\x92"; + const ARROW_LEFT = "\xEE\x80\x92"; + const UP = "\xEE\x80\x93"; + const ARROW_UP = "\xEE\x80\x93"; + const RIGHT = "\xEE\x80\x94"; + const ARROW_RIGHT = "\xEE\x80\x94"; + const DOWN = "\xEE\x80\x95"; + const ARROW_DOWN = "\xEE\x80\x95"; + const INSERT = "\xEE\x80\x96"; + const DELETE = "\xEE\x80\x97"; + const SEMICOLON = "\xEE\x80\x98"; + const EQUALS = "\xEE\x80\x99"; + const NUMPAD0 = "\xEE\x80\x9A"; + const NUMPAD1 = "\xEE\x80\x9B"; + const NUMPAD2 = "\xEE\x80\x9C"; + const NUMPAD3 = "\xEE\x80\x9D"; + const NUMPAD4 = "\xEE\x80\x9E"; + const NUMPAD5 = "\xEE\x80\x9F"; + const NUMPAD6 = "\xEE\x80\xA0"; + const NUMPAD7 = "\xEE\x80\xA1"; + const NUMPAD8 = "\xEE\x80\xA2"; + const NUMPAD9 = "\xEE\x80\xA3"; + const MULTIPLY = "\xEE\x80\xA4"; + const ADD = "\xEE\x80\xA5"; + const SEPARATOR = "\xEE\x80\xA6"; + const SUBTRACT = "\xEE\x80\xA7"; + const DECIMAL = "\xEE\x80\xA8"; + const DIVIDE = "\xEE\x80\xA9"; + const F1 = "\xEE\x80\xB1"; + const F2 = "\xEE\x80\xB2"; + const F3 = "\xEE\x80\xB3"; + const F4 = "\xEE\x80\xB4"; + const F5 = "\xEE\x80\xB5"; + const F6 = "\xEE\x80\xB6"; + const F7 = "\xEE\x80\xB7"; + const F8 = "\xEE\x80\xB8"; + const F9 = "\xEE\x80\xB9"; + const F10 = "\xEE\x80\xBA"; + const F11 = "\xEE\x80\xBB"; + const F12 = "\xEE\x80\xBC"; + const META = "\xEE\x80\xBD"; + const COMMAND = "\xEE\x80\xBD"; // ALIAS + const ZENKAKU_HANKAKU = "\xEE\x80\xC0"; - const NULL = "\xEE\x80\x80"; - const CANCEL = "\xEE\x80\x81"; - const HELP = "\xEE\x80\x82"; - const BACKSPACE = "\xEE\x80\x83"; - const TAB = "\xEE\x80\x84"; - const CLEAR = "\xEE\x80\x85"; - const RETURN_KEY = "\xEE\x80\x86"; // php does not allow RETURN - const ENTER = "\xEE\x80\x87"; - const SHIFT = "\xEE\x80\x88"; - const LEFT_SHIFT = "\xEE\x80\x88"; - const CONTROL = "\xEE\x80\x89"; - const LEFT_CONTROL = "\xEE\x80\x89"; - const ALT = "\xEE\x80\x8A"; - const LEFT_ALT = "\xEE\x80\x8A"; - const PAUSE = "\xEE\x80\x8B"; - const ESCAPE = "\xEE\x80\x8C"; - const SPACE = "\xEE\x80\x8D"; - const PAGE_UP = "\xEE\x80\x8E"; - const PAGE_DOWN = "\xEE\x80\x8F"; - const END = "\xEE\x80\x90"; - const HOME = "\xEE\x80\x91"; - const LEFT = "\xEE\x80\x92"; - const ARROW_LEFT = "\xEE\x80\x92"; - const UP = "\xEE\x80\x93"; - const ARROW_UP = "\xEE\x80\x93"; - const RIGHT = "\xEE\x80\x94"; - const ARROW_RIGHT = "\xEE\x80\x94"; - const DOWN = "\xEE\x80\x95"; - const ARROW_DOWN = "\xEE\x80\x95"; - const INSERT = "\xEE\x80\x96"; - const DELETE = "\xEE\x80\x97"; - const SEMICOLON = "\xEE\x80\x98"; - const EQUALS = "\xEE\x80\x99"; - const NUMPAD0 = "\xEE\x80\x9A"; - const NUMPAD1 = "\xEE\x80\x9B"; - const NUMPAD2 = "\xEE\x80\x9C"; - const NUMPAD3 = "\xEE\x80\x9D"; - const NUMPAD4 = "\xEE\x80\x9E"; - const NUMPAD5 = "\xEE\x80\x9F"; - const NUMPAD6 = "\xEE\x80\xA0"; - const NUMPAD7 = "\xEE\x80\xA1"; - const NUMPAD8 = "\xEE\x80\xA2"; - const NUMPAD9 = "\xEE\x80\xA3"; - const MULTIPLY = "\xEE\x80\xA4"; - const ADD = "\xEE\x80\xA5"; - const SEPARATOR = "\xEE\x80\xA6"; - const SUBTRACT = "\xEE\x80\xA7"; - const DECIMAL = "\xEE\x80\xA8"; - const DIVIDE = "\xEE\x80\xA9"; - const F1 = "\xEE\x80\xB1"; - const F2 = "\xEE\x80\xB2"; - const F3 = "\xEE\x80\xB3"; - const F4 = "\xEE\x80\xB4"; - const F5 = "\xEE\x80\xB5"; - const F6 = "\xEE\x80\xB6"; - const F7 = "\xEE\x80\xB7"; - const F8 = "\xEE\x80\xB8"; - const F9 = "\xEE\x80\xB9"; - const F10 = "\xEE\x80\xBA"; - const F11 = "\xEE\x80\xBB"; - const F12 = "\xEE\x80\xBC"; - const META = "\xEE\x80\xBD"; - const COMMAND = "\xEE\x80\xBD"; // ALIAS - const ZENKAKU_HANKAKU = "\xEE\x80\xC0"; + /** + * Encode input of `sendKeys()`. + * @param string|array $keys + * @return array + */ + public static function encode($keys) + { + if (is_numeric($keys)) { + $keys = '' . $keys; + } - /** - * Encode input of `sendKeys()`. - * @param string|array $keys - * @return array - */ - public static function encode($keys) { + if (is_string($keys)) { + $keys = array($keys); + } - if (is_numeric($keys)) { - $keys = '' . $keys; - } - - if (is_string($keys)) { - $keys = array($keys); - } + $encoded = array(); + foreach ($keys as $key) { + if (is_array($key)) { + // handle modified keys + $key = implode('', $key) . self::NULL; + } + $encoded[] = (string) $key; + } - $encoded = array(); - foreach ($keys as $key) { - if (is_array($key)) { - // handle modified keys - $key = implode('', $key).self::NULL; - } - $encoded[] = (string)$key; + return $encoded; } - - return $encoded; - } } diff --git a/lib/WebDriverMouse.php b/lib/WebDriverMouse.php index 847bc2cd0..9fe052119 100644 --- a/lib/WebDriverMouse.php +++ b/lib/WebDriverMouse.php @@ -20,45 +20,47 @@ /** * Interface representing basic mouse operations. */ -interface WebDriverMouse { +interface WebDriverMouse +{ + /** + * @param WebDriverCoordinates $where + * @return WebDriverMouse + */ + public function click(WebDriverCoordinates $where); - /** - * @param WebDriverCoordinates $where - * @return WebDriverMouse - */ - public function click(WebDriverCoordinates $where); + /** + * @param WebDriverCoordinates $where + * @return WebDriverMouse + */ + public function contextClick(WebDriverCoordinates $where); - /** - * @param WebDriverCoordinates $where - * @return WebDriverMouse - */ - public function contextClick(WebDriverCoordinates $where); + /** + * @param WebDriverCoordinates $where + * @return WebDriverMouse + */ + public function doubleClick(WebDriverCoordinates $where); - /** - * @param WebDriverCoordinates $where - * @return WebDriverMouse - */ - public function doubleClick(WebDriverCoordinates $where); + /** + * @param WebDriverCoordinates $where + * @return WebDriverMouse + */ + public function mouseDown(WebDriverCoordinates $where); - /** - * @param WebDriverCoordinates $where - * @return WebDriverMouse - */ - public function mouseDown(WebDriverCoordinates $where); + /** + * @param WebDriverCoordinates $where + * @param int $x_offset + * @param int $y_offset + * @return WebDriverMouse + */ + public function mouseMove( + WebDriverCoordinates $where, + $x_offset = null, + $y_offset = null + ); - /** - * @param WebDriverCoordinates $where - * @param int $x_offset - * @param int $y_offset - * @return WebDriverMouse - */ - public function mouseMove(WebDriverCoordinates $where, - $x_offset = null, - $y_offset = null); - - /** - * @param WebDriverCoordinates $where - * @return WebDriverMouse - */ - public function mouseUp(WebDriverCoordinates $where); + /** + * @param WebDriverCoordinates $where + * @return WebDriverMouse + */ + public function mouseUp(WebDriverCoordinates $where); } diff --git a/lib/WebDriverNavigation.php b/lib/WebDriverNavigation.php index 8dd382dea..5e06d6257 100644 --- a/lib/WebDriverNavigation.php +++ b/lib/WebDriverNavigation.php @@ -27,53 +27,62 @@ * FirefoxProfile preferences. * https://code.google.com/p/selenium/wiki/DesiredCapabilities#settings */ -class WebDriverNavigation { +class WebDriverNavigation +{ + protected $executor; - protected $executor; + public function __construct(ExecuteMethod $executor) + { + $this->executor = $executor; + } - public function __construct(ExecuteMethod $executor) { - $this->executor = $executor; - } + /** + * Move back a single entry in the browser's history, if possible. + * + * @return WebDriverNavigation The instance. + */ + public function back() + { + $this->executor->execute(DriverCommand::GO_BACK); - /** - * Move back a single entry in the browser's history, if possible. - * - * @return WebDriverNavigation The instance. - */ - public function back() { - $this->executor->execute(DriverCommand::GO_BACK); - return $this; - } + return $this; + } - /** - * Move forward a single entry in the browser's history, if possible. - * - * @return WebDriverNavigation The instance. - */ - public function forward() { - $this->executor->execute(DriverCommand::GO_FORWARD); - return $this; - } + /** + * Move forward a single entry in the browser's history, if possible. + * + * @return WebDriverNavigation The instance. + */ + public function forward() + { + $this->executor->execute(DriverCommand::GO_FORWARD); - /** - * Refresh the current page. - * - * @return WebDriverNavigation The instance. - */ - public function refresh() { - $this->executor->execute(DriverCommand::REFRESH); - return $this; - } + return $this; + } - /** - * Navigate to the given URL. - * - * @param string $url - * @return WebDriverNavigation The instance. - */ - public function to($url) { - $params = array('url' => (string)$url); - $this->executor->execute(DriverCommand::GET, $params); - return $this; - } + /** + * Refresh the current page. + * + * @return WebDriverNavigation The instance. + */ + public function refresh() + { + $this->executor->execute(DriverCommand::REFRESH); + + return $this; + } + + /** + * Navigate to the given URL. + * + * @param string $url + * @return WebDriverNavigation The instance. + */ + public function to($url) + { + $params = array('url' => (string) $url); + $this->executor->execute(DriverCommand::GET, $params); + + return $this; + } } diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index 9f48b05d1..8b80d3dba 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -22,152 +22,170 @@ /** * Managing stuff you would do in a browser. */ -class WebDriverOptions { - - protected $executor; - - public function __construct(ExecuteMethod $executor) { - $this->executor = $executor; - } - - /** - * Add a specific cookie. - * - * Here are the valid attributes of a cookie array. - * 'name' : string The name of the cookie; may not be null or an empty - * string. - * 'value' : string The cookie value; may not be null. - * 'path' : string The path the cookie is visible to. If left blank or set - * to null, will be set to "/". - * 'domain': string The domain the cookie is visible to. It should be null or - * the same as the domain of the current URL. - * 'secure': bool Whether this cookie requires a secure connection(https?). - * It should be null or equal to the security of the current - * URL. - * 'expiry': int The cookie's expiration date; may be null. - * - * @param array $cookie An array with key as the attributes mentioned above. - * @return WebDriverOptions The current instance. - */ - public function addCookie(array $cookie) { - $this->validate($cookie); - $this->executor->execute( - DriverCommand::ADD_COOKIE, - array('cookie' => $cookie) - ); - return $this; - } - - /** - * Delete all the cookies that are currently visible. - * - * @return WebDriverOptions The current instance. - */ - public function deleteAllCookies() { - $this->executor->execute(DriverCommand::DELETE_ALL_COOKIES); - return $this; - } - - /** - * Delete the cookie with the give name. - * - * @param string $name - * @return WebDriverOptions The current instance. - */ - public function deleteCookieNamed($name) { - $this->executor->execute( - DriverCommand::DELETE_COOKIE, - array(':name' => $name) - ); - return $this; - } - - /** - * Get the cookie with a given name. - * - * @param string $name - * @return array The cookie, or null if no cookie with the given name is - * presented. - */ - public function getCookieNamed($name) { - $cookies = $this->getCookies(); - foreach ($cookies as $cookie) { - if ($cookie['name'] === $name) { - return $cookie; - } +class WebDriverOptions +{ + protected $executor; + + public function __construct(ExecuteMethod $executor) + { + $this->executor = $executor; + } + + /** + * Add a specific cookie. + * + * Here are the valid attributes of a cookie array. + * 'name' : string The name of the cookie; may not be null or an empty + * string. + * 'value' : string The cookie value; may not be null. + * 'path' : string The path the cookie is visible to. If left blank or set + * to null, will be set to "/". + * 'domain': string The domain the cookie is visible to. It should be null or + * the same as the domain of the current URL. + * 'secure': bool Whether this cookie requires a secure connection(https?). + * It should be null or equal to the security of the current + * URL. + * 'expiry': int The cookie's expiration date; may be null. + * + * @param array $cookie An array with key as the attributes mentioned above. + * @return WebDriverOptions The current instance. + */ + public function addCookie(array $cookie) + { + $this->validate($cookie); + $this->executor->execute( + DriverCommand::ADD_COOKIE, + array('cookie' => $cookie) + ); + + return $this; + } + + /** + * Delete all the cookies that are currently visible. + * + * @return WebDriverOptions The current instance. + */ + public function deleteAllCookies() + { + $this->executor->execute(DriverCommand::DELETE_ALL_COOKIES); + + return $this; + } + + /** + * Delete the cookie with the give name. + * + * @param string $name + * @return WebDriverOptions The current instance. + */ + public function deleteCookieNamed($name) + { + $this->executor->execute( + DriverCommand::DELETE_COOKIE, + array(':name' => $name) + ); + + return $this; } - return null; - } - - /** - * Get all the cookies for the current domain. - * - * @return array The array of cookies presented. - */ - public function getCookies() { - return $this->executor->execute(DriverCommand::GET_ALL_COOKIES); - } - - private function validate(array $cookie) { - if (!isset($cookie['name']) || - $cookie['name'] === '' || - strpos($cookie['name'], ';') !== false) { - throw new InvalidArgumentException( - '"name" should be non-empty and does not contain a ";"'); + + /** + * Get the cookie with a given name. + * + * @param string $name + * @return array The cookie, or null if no cookie with the given name is + * presented. + */ + public function getCookieNamed($name) + { + $cookies = $this->getCookies(); + foreach ($cookies as $cookie) { + if ($cookie['name'] === $name) { + return $cookie; + } + } + + return null; + } + + /** + * Get all the cookies for the current domain. + * + * @return array The array of cookies presented. + */ + public function getCookies() + { + return $this->executor->execute(DriverCommand::GET_ALL_COOKIES); + } + + private function validate(array $cookie) + { + if (!isset($cookie['name']) || + $cookie['name'] === '' || + strpos($cookie['name'], ';') !== false + ) { + throw new InvalidArgumentException( + '"name" should be non-empty and does not contain a ";"' + ); + } + + if (!isset($cookie['value'])) { + throw new InvalidArgumentException( + '"value" is required when setting a cookie.' + ); + } + + if (isset($cookie['domain']) && strpos($cookie['domain'], ':') !== false) { + throw new InvalidArgumentException( + '"domain" should not contain a port:' . (string) $cookie['domain'] + ); + } + } + + /** + * Return the interface for managing driver timeouts. + * + * @return WebDriverTimeouts + */ + public function timeouts() + { + return new WebDriverTimeouts($this->executor); } - if (!isset($cookie['value'])) { - throw new InvalidArgumentException( - '"value" is required when setting a cookie.'); + /** + * An abstraction allowing the driver to manipulate the browser's window + * + * @return WebDriverWindow + * @see WebDriverWindow + */ + public function window() + { + return new WebDriverWindow($this->executor); } - if (isset($cookie['domain']) && strpos($cookie['domain'], ':') !== false) { - throw new InvalidArgumentException( - '"domain" should not contain a port:'.(string)$cookie['domain']); + /** + * Get the log for a given log type. Log buffer is reset after each request. + * + * @param string $log_type The log type. + * @return array The list of log entries. + * @see https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Type + */ + public function getLog($log_type) + { + return $this->executor->execute( + DriverCommand::GET_LOG, + array('type' => $log_type) + ); } - } - - /** - * Return the interface for managing driver timeouts. - * - * @return WebDriverTimeouts - */ - public function timeouts() { - return new WebDriverTimeouts($this->executor); - } - - /** - * An abstraction allowing the driver to manipulate the browser's window - * - * @return WebDriverWindow - * @see WebDriverWindow - */ - public function window() { - return new WebDriverWindow($this->executor); - } - - /** - * Get the log for a given log type. Log buffer is reset after each request. - * - * @param string $log_type The log type. - * @return array The list of log entries. - * @see https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Type - */ - public function getLog($log_type) { - return $this->executor->execute( - DriverCommand::GET_LOG, - array('type' => $log_type) - ); - } - - /** - * Get available log types. - * - * @return array The list of available log types. - * @see https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Type - */ - public function getAvailableLogTypes() { - return $this->executor->execute(DriverCommand::GET_AVAILABLE_LOG_TYPES); - } + /** + * Get available log types. + * + * @return array The list of available log types. + * @see https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Type + */ + public function getAvailableLogTypes() + { + return $this->executor->execute(DriverCommand::GET_AVAILABLE_LOG_TYPES); + } } diff --git a/lib/WebDriverPlatform.php b/lib/WebDriverPlatform.php index 9dc42fabd..bb1923556 100644 --- a/lib/WebDriverPlatform.php +++ b/lib/WebDriverPlatform.php @@ -18,17 +18,18 @@ /** * The platforms supported by WebDriver. */ -class WebDriverPlatform { - const ANDROID = 'ANDROID'; - const ANY = 'ANY'; - const LINUX = 'LINUX'; - const MAC = 'MAC'; - const UNIX = 'UNIX'; - const VISTA = 'VISTA'; - const WINDOWS = 'WINDOWS'; - const XP = 'XP'; +class WebDriverPlatform +{ + const ANDROID = 'ANDROID'; + const ANY = 'ANY'; + const LINUX = 'LINUX'; + const MAC = 'MAC'; + const UNIX = 'UNIX'; + const VISTA = 'VISTA'; + const WINDOWS = 'WINDOWS'; + const XP = 'XP'; - private function __construct() - { - } + private function __construct() + { + } } diff --git a/lib/WebDriverPoint.php b/lib/WebDriverPoint.php index 0653eb988..e12977b22 100644 --- a/lib/WebDriverPoint.php +++ b/lib/WebDriverPoint.php @@ -18,67 +18,76 @@ /** * Represent a point. */ -class WebDriverPoint { +class WebDriverPoint +{ + private $x; + private $y; - private $x, $y; + public function __construct($x, $y) + { + $this->x = $x; + $this->y = $y; + } - public function __construct($x, $y) { - $this->x = $x; - $this->y = $y; - } + /** + * Get the x-coordinate. + * + * @return int The x-coordinate of the point. + */ + public function getX() + { + return $this->x; + } - /** - * Get the x-coordinate. - * - * @return int The x-coordinate of the point. - */ - public function getX() { - return $this->x; - } + /** + * Get the y-coordinate. + * + * @return int The y-coordinate of the point. + */ + public function getY() + { + return $this->y; + } - /** - * Get the y-coordinate. - * - * @return int The y-coordinate of the point. - */ - public function getY() { - return $this->y; - } + /** + * Set the point to a new position. + * + * @param int $new_x + * @param int $new_y + * @return WebDriverPoint The same instance with updated coordinates. + */ + public function move($new_x, $new_y) + { + $this->x = $new_x; + $this->y = $new_y; - /** - * Set the point to a new position. - * - * @param int $new_x - * @param int $new_y - * @return WebDriverPoint The same instance with updated coordinates. - */ - public function move($new_x, $new_y) { - $this->x = $new_x; - $this->y = $new_y; - return $this; - } + return $this; + } - /** - * Move the current by offsets. - * - * @param int $x_offset - * @param int $y_offset - * @return WebDriverPoint The same instance with updated coordinates. - */ - public function moveBy($x_offset, $y_offset) { - $this->x += $x_offset; - $this->y += $y_offset; - return $this; - } + /** + * Move the current by offsets. + * + * @param int $x_offset + * @param int $y_offset + * @return WebDriverPoint The same instance with updated coordinates. + */ + public function moveBy($x_offset, $y_offset) + { + $this->x += $x_offset; + $this->y += $y_offset; - /** - * Check whether the given point is the same as the instance. - * - * @param WebDriverPoint $point The point to be compared with. - * @return bool Whether the x and y coordinates are the same as the instance. - */ - public function equals(WebDriverPoint $point) { - return $this->x === $point->getX() && - $this->y === $point->getY(); - } + return $this; + } + + /** + * Check whether the given point is the same as the instance. + * + * @param WebDriverPoint $point The point to be compared with. + * @return bool Whether the x and y coordinates are the same as the instance. + */ + public function equals(WebDriverPoint $point) + { + return $this->x === $point->getX() && + $this->y === $point->getY(); + } } diff --git a/lib/WebDriverSearchContext.php b/lib/WebDriverSearchContext.php index d9cff1038..4d784c682 100644 --- a/lib/WebDriverSearchContext.php +++ b/lib/WebDriverSearchContext.php @@ -19,26 +19,26 @@ * The interface for WebDriver and WebDriverElement which is able to search for * WebDriverElement inside. */ -interface WebDriverSearchContext { +interface WebDriverSearchContext +{ + /** + * Find the first WebDriverElement within this element using the given + * mechanism. + * + * @param WebDriverBy $locator + * @return WebDriverElement NoSuchElementException is thrown in + * HttpCommandExecutor if no element is found. + * @see WebDriverBy + */ + public function findElement(WebDriverBy $locator); - /** - * Find the first WebDriverElement within this element using the given - * mechanism. - * - * @param WebDriverBy $locator - * @return WebDriverElement NoSuchElementException is thrown in - * HttpCommandExecutor if no element is found. - * @see WebDriverBy - */ - public function findElement(WebDriverBy $locator); - - /** - * Find all WebDriverElements within this element using the given mechanism. - * - * @param WebDriverBy $locator - * @return WebDriverElement[] A list of all WebDriverElements, or an empty array if - * nothing matches - * @see WebDriverBy - */ - public function findElements(WebDriverBy $locator); + /** + * Find all WebDriverElements within this element using the given mechanism. + * + * @param WebDriverBy $locator + * @return WebDriverElement[] A list of all WebDriverElements, or an empty array if + * nothing matches + * @see WebDriverBy + */ + public function findElements(WebDriverBy $locator); } diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index 20082dd0b..158690b2f 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -15,289 +15,291 @@ namespace Facebook\WebDriver; -use Facebook\WebDriver\Exception\UnexpectedTagNameException; use Facebook\WebDriver\Exception\NoSuchElementException; +use Facebook\WebDriver\Exception\UnexpectedTagNameException; use Facebook\WebDriver\Exception\UnsupportedOperationException; /** * Models a SELECT tag, providing helper methods to select and deselect options. */ -class WebDriverSelect { +class WebDriverSelect +{ + private $element; + private $isMulti; - private $element; - private $isMulti; + public function __construct(WebDriverElement $element) + { + $tag_name = $element->getTagName(); - public function __construct(WebDriverElement $element) { - $tag_name = $element->getTagName(); - - if ($tag_name !== 'select') { - throw new UnexpectedTagNameException('select', $tag_name); + if ($tag_name !== 'select') { + throw new UnexpectedTagNameException('select', $tag_name); + } + $this->element = $element; + $value = $element->getAttribute('multiple'); + $this->isMulti = ($value === 'true'); } - $this->element = $element; - $value = $element->getAttribute('multiple'); - $this->isMulti = ($value === 'true'); - } - /** - * @return bool Whether this select element support selecting multiple - * options. This is done by checking the value of the 'multiple' - * attribute. - */ - public function isMultiple() { - return $this->isMulti; - } - - /** - * @return WebDriverElement[] All options belonging to this select tag. - */ - public function getOptions() { - return $this->element->findElements(WebDriverBy::tagName('option')); - } - - /** - * @return WebDriverElement[] All selected options belonging to this select tag. - */ - public function getAllSelectedOptions() { - $selected_options = array(); - foreach ($this->getOptions() as $option) { - if ($option->isSelected()) { - $selected_options[] = $option; - } + /** + * @return bool Whether this select element support selecting multiple + * options. This is done by checking the value of the 'multiple' + * attribute. + */ + public function isMultiple() + { + return $this->isMulti; } - return $selected_options; - } - /** - * @throws NoSuchElementException - * - * @return WebDriverElement The first selected option in this select tag (or - * the currently selected option in a normal select) - */ - public function getFirstSelectedOption() { - foreach ($this->getOptions() as $option) { - if ($option->isSelected()) { - return $option; - } + /** + * @return WebDriverElement[] All options belonging to this select tag. + */ + public function getOptions() + { + return $this->element->findElements(WebDriverBy::tagName('option')); } - throw new NoSuchElementException('No options are selected'); - } + /** + * @return WebDriverElement[] All selected options belonging to this select tag. + */ + public function getAllSelectedOptions() + { + $selected_options = array(); + foreach ($this->getOptions() as $option) { + if ($option->isSelected()) { + $selected_options[] = $option; + } + } - /** - * Deselect all options in multiple select tag. - * - * @throws UnsupportedOperationException - * - * @return void - */ - public function deselectAll() { - if (!$this->isMultiple()) { - throw new UnsupportedOperationException( - 'You may only deselect all options of a multi-select' - ); + return $selected_options; } - foreach ($this->getOptions() as $option) { - if ($option->isSelected()) { - $option->click(); - } + /** + * @throws NoSuchElementException + * + * @return WebDriverElement The first selected option in this select tag (or + * the currently selected option in a normal select) + */ + public function getFirstSelectedOption() + { + foreach ($this->getOptions() as $option) { + if ($option->isSelected()) { + return $option; + } + } + + throw new NoSuchElementException('No options are selected'); } - } - /** - * Select the option at the given index. - * - * @param int $index The index of the option. (0-based) - * - * @throws NoSuchElementException - * - * @return void - */ - public function selectByIndex($index) { - $matched = false; - foreach ($this->getOptions() as $option) { - if ($option->getAttribute('index') === (string)$index) { - if (!$option->isSelected()) { - $option->click(); - if (!$this->isMultiple()) { - return; - } + /** + * Deselect all options in multiple select tag. + * + * @throws UnsupportedOperationException + */ + public function deselectAll() + { + if (!$this->isMultiple()) { + throw new UnsupportedOperationException( + 'You may only deselect all options of a multi-select' + ); + } + + foreach ($this->getOptions() as $option) { + if ($option->isSelected()) { + $option->click(); + } } - $matched = true; - } } - if (!$matched) { - throw new NoSuchElementException( - sprintf('Cannot locate option with index: %d', $index) - ); + + /** + * Select the option at the given index. + * + * @param int $index The index of the option. (0-based) + * + * @throws NoSuchElementException + */ + public function selectByIndex($index) + { + $matched = false; + foreach ($this->getOptions() as $option) { + if ($option->getAttribute('index') === (string) $index) { + if (!$option->isSelected()) { + $option->click(); + if (!$this->isMultiple()) { + return; + } + } + $matched = true; + } + } + if (!$matched) { + throw new NoSuchElementException( + sprintf('Cannot locate option with index: %d', $index) + ); + } } - } - /** - * Select all options that have value attribute matching the argument. That - * is, when given "foo" this would select an option like: - * - * ; - * - * @param string $value The value to match against. - * - * @throws NoSuchElementException - * - * @return void - */ - public function selectByValue($value) { - $matched = false; - $xpath = './/option[@value = '.$this->escapeQuotes($value).']'; - $options = $this->element->findElements(WebDriverBy::xpath($xpath)); + /** + * Select all options that have value attribute matching the argument. That + * is, when given "foo" this would select an option like: + * + * ; + * + * @param string $value The value to match against. + * + * @throws NoSuchElementException + */ + public function selectByValue($value) + { + $matched = false; + $xpath = './/option[@value = ' . $this->escapeQuotes($value) . ']'; + $options = $this->element->findElements(WebDriverBy::xpath($xpath)); - foreach ($options as $option) { - if (!$option->isSelected()) { - $option->click(); - } - if (!$this->isMultiple()) { - return; - } - $matched = true; - } + foreach ($options as $option) { + if (!$option->isSelected()) { + $option->click(); + } + if (!$this->isMultiple()) { + return; + } + $matched = true; + } - if (!$matched) { - throw new NoSuchElementException( - sprintf('Cannot locate option with value: %s', $value) - ); + if (!$matched) { + throw new NoSuchElementException( + sprintf('Cannot locate option with value: %s', $value) + ); + } } - } - /** - * Select all options that display text matching the argument. That is, when - * given "Bar" this would select an option like: - * - * ; - * - * @param string $text The visible text to match against. - * - * @throws NoSuchElementException - * - * @return void - */ - public function selectByVisibleText($text) { - $matched = false; - $xpath = './/option[normalize-space(.) = '.$this->escapeQuotes($text).']'; - $options = $this->element->findElements(WebDriverBy::xpath($xpath)); + /** + * Select all options that display text matching the argument. That is, when + * given "Bar" this would select an option like: + * + * ; + * + * @param string $text The visible text to match against. + * + * @throws NoSuchElementException + */ + public function selectByVisibleText($text) + { + $matched = false; + $xpath = './/option[normalize-space(.) = ' . $this->escapeQuotes($text) . ']'; + $options = $this->element->findElements(WebDriverBy::xpath($xpath)); - foreach ($options as $option) { - if (!$option->isSelected()) { - $option->click(); - } - if (!$this->isMultiple()) { - return; - } - $matched = true; - } + foreach ($options as $option) { + if (!$option->isSelected()) { + $option->click(); + } + if (!$this->isMultiple()) { + return; + } + $matched = true; + } - // Since the mechanism of getting the text in xpath is not the same as - // webdriver, use the expensive getText() to check if nothing is matched. - if (!$matched) { - foreach ($this->getOptions() as $option) { - if ($option->getText() === $text) { - if (!$option->isSelected()) { - $option->click(); - } - if (!$this->isMultiple()) { - return; - } - $matched = true; + // Since the mechanism of getting the text in xpath is not the same as + // webdriver, use the expensive getText() to check if nothing is matched. + if (!$matched) { + foreach ($this->getOptions() as $option) { + if ($option->getText() === $text) { + if (!$option->isSelected()) { + $option->click(); + } + if (!$this->isMultiple()) { + return; + } + $matched = true; + } + } } - } - } - if (!$matched) { - throw new NoSuchElementException( - sprintf('Cannot locate option with text: %s', $text) - ); + if (!$matched) { + throw new NoSuchElementException( + sprintf('Cannot locate option with text: %s', $text) + ); + } } - } - /** - * Deselect the option at the given index. - * - * @param int $index The index of the option. (0-based) - * @return void - */ - public function deselectByIndex($index) { - foreach ($this->getOptions() as $option) { - if ($option->getAttribute('index') === (string)$index && - $option->isSelected()) { - $option->click(); - } + /** + * Deselect the option at the given index. + * + * @param int $index The index of the option. (0-based) + */ + public function deselectByIndex($index) + { + foreach ($this->getOptions() as $option) { + if ($option->getAttribute('index') === (string) $index && $option->isSelected()) { + $option->click(); + } + } } - } - /** - * Deselect all options that have value attribute matching the argument. That - * is, when given "foo" this would select an option like: - * - * ; - * - * @param string $value The value to match against. - * @return void - */ - public function deselectByValue($value) { - $xpath = './/option[@value = '.$this->escapeQuotes($value).']'; - $options = $this->element->findElements(WebDriverBy::xpath($xpath)); - foreach ($options as $option) { - if ($option->isSelected()) { - $option->click(); - } + /** + * Deselect all options that have value attribute matching the argument. That + * is, when given "foo" this would select an option like: + * + * ; + * + * @param string $value The value to match against. + */ + public function deselectByValue($value) + { + $xpath = './/option[@value = ' . $this->escapeQuotes($value) . ']'; + $options = $this->element->findElements(WebDriverBy::xpath($xpath)); + foreach ($options as $option) { + if ($option->isSelected()) { + $option->click(); + } + } } - } - /** - * Deselect all options that display text matching the argument. That is, when - * given "Bar" this would select an option like: - * - * ; - * - * @param string $text The visible text to match against. - * @return void - */ - public function deselectByVisibleText($text) { - $xpath = './/option[normalize-space(.) = '.$this->escapeQuotes($text).']'; - $options = $this->element->findElements(WebDriverBy::xpath($xpath)); - foreach ($options as $option) { - if ($option->isSelected()) { - $option->click(); - } + /** + * Deselect all options that display text matching the argument. That is, when + * given "Bar" this would select an option like: + * + * ; + * + * @param string $text The visible text to match against. + */ + public function deselectByVisibleText($text) + { + $xpath = './/option[normalize-space(.) = ' . $this->escapeQuotes($text) . ']'; + $options = $this->element->findElements(WebDriverBy::xpath($xpath)); + foreach ($options as $option) { + if ($option->isSelected()) { + $option->click(); + } + } } - } - /** - * Convert strings with both quotes and ticks into: - * foo'"bar -> concat("foo'", '"', "bar") - * - * @param string $to_escape The string to be converted. - * @return string The escaped string. - */ - protected function escapeQuotes($to_escape) { - if (strpos($to_escape, '"') !== false && strpos($to_escape, "'") !== false) { - $substrings = explode('"', $to_escape); + /** + * Convert strings with both quotes and ticks into: + * foo'"bar -> concat("foo'", '"', "bar") + * + * @param string $to_escape The string to be converted. + * @return string The escaped string. + */ + protected function escapeQuotes($to_escape) + { + if (strpos($to_escape, '"') !== false && strpos($to_escape, "'") !== false) { + $substrings = explode('"', $to_escape); - $escaped = "concat("; - $first = true; - foreach ($substrings as $string) { - if (!$first) { - $escaped .= ", '\"',"; - $first = false; - } - $escaped .= '"' . $string . '"'; - } - return $escaped; - } + $escaped = 'concat('; + $first = true; + foreach ($substrings as $string) { + if (!$first) { + $escaped .= ", '\"',"; + $first = false; + } + $escaped .= '"' . $string . '"'; + } - if (strpos($to_escape, '"') !== false) { - return sprintf("'%s'", $to_escape); - } + return $escaped; + } - return sprintf('"%s"', $to_escape); - } + if (strpos($to_escape, '"') !== false) { + return sprintf("'%s'", $to_escape); + } + return sprintf('"%s"', $to_escape); + } } diff --git a/lib/WebDriverTargetLocator.php b/lib/WebDriverTargetLocator.php index 86e0939b8..d9fdf5c18 100644 --- a/lib/WebDriverTargetLocator.php +++ b/lib/WebDriverTargetLocator.php @@ -18,47 +18,47 @@ /** * Used to locate a given frame or window. */ -interface WebDriverTargetLocator { +interface WebDriverTargetLocator +{ + /** + * Switch to the main document if the page contains iframes. Otherwise, switch + * to the first frame on the page. + * + * @return WebDriver The driver focused on the top window or the first frame. + */ + public function defaultContent(); - /** - * Switch to the main document if the page contains iframes. Otherwise, switch - * to the first frame on the page. - * - * @return WebDriver The driver focused on the top window or the first frame. - */ - public function defaultContent(); + /** + * Switch to the iframe by its id or name. + * + * @param WebDriverElement|string $frame The WebDriverElement, + * the id or the name of the frame. + * @return WebDriver The driver focused on the given frame. + */ + public function frame($frame); - /** - * Switch to the iframe by its id or name. - * - * @param WebDriverElement|string $frame The WebDriverElement, - * the id or the name of the frame. - * @return WebDriver The driver focused on the given frame. - */ - public function frame($frame); + /** + * Switch the focus to another window by its handle. + * + * @param string $handle The handle of the window to be focused on. + * @return WebDriver Tge driver focused on the given window. + * @see WebDriver::getWindowHandles + */ + public function window($handle); - /** - * Switch the focus to another window by its handle. - * - * @param string $handle The handle of the window to be focused on. - * @return WebDriver Tge driver focused on the given window. - * @see WebDriver::getWindowHandles - */ - public function window($handle); + /** + * Switch to the currently active modal dialog for this particular driver + * instance. + * + * @return WebDriverAlert + */ + public function alert(); - /** - * Switch to the currently active modal dialog for this particular driver - * instance. - * - * @return WebDriverAlert - */ - public function alert(); - - /** - * Switches to the element that currently has focus within the document - * currently "switched to", or the body element if this cannot be detected. - * - * @return WebDriverElement - */ - public function activeElement(); + /** + * Switches to the element that currently has focus within the document + * currently "switched to", or the body element if this cannot be detected. + * + * @return WebDriverElement + */ + public function activeElement(); } diff --git a/lib/WebDriverTimeouts.php b/lib/WebDriverTimeouts.php index 2af6882ec..50b62f24f 100644 --- a/lib/WebDriverTimeouts.php +++ b/lib/WebDriverTimeouts.php @@ -20,56 +20,63 @@ /** * Managing timeout behavior for WebDriver instances. */ -class WebDriverTimeouts { +class WebDriverTimeouts +{ + protected $executor; - protected $executor; + public function __construct($executor) + { + $this->executor = $executor; + } - public function __construct($executor) { - $this->executor = $executor; - } + /** + * Specify the amount of time the driver should wait when searching for an + * element if it is not immediately present. + * + * @param int $seconds Wait time in second. + * @return WebDriverTimeouts The current instance. + */ + public function implicitlyWait($seconds) + { + $this->executor->execute( + DriverCommand::IMPLICITLY_WAIT, + array('ms' => $seconds * 1000) + ); - /** - * Specify the amount of time the driver should wait when searching for an - * element if it is not immediately present. - * - * @param int $seconds Wait time in second. - * @return WebDriverTimeouts The current instance. - */ - public function implicitlyWait($seconds) { - $this->executor->execute( - DriverCommand::IMPLICITLY_WAIT, - array('ms' => $seconds * 1000) - ); - return $this; - } + return $this; + } - /** - * Set the amount of time to wait for an asynchronous script to finish - * execution before throwing an error. - * - * @param int $seconds Wait time in second. - * @return WebDriverTimeouts The current instance. - */ - public function setScriptTimeout($seconds) { - $this->executor->execute( - DriverCommand::SET_SCRIPT_TIMEOUT, - array('ms' => $seconds * 1000) - ); - return $this; - } + /** + * Set the amount of time to wait for an asynchronous script to finish + * execution before throwing an error. + * + * @param int $seconds Wait time in second. + * @return WebDriverTimeouts The current instance. + */ + public function setScriptTimeout($seconds) + { + $this->executor->execute( + DriverCommand::SET_SCRIPT_TIMEOUT, + array('ms' => $seconds * 1000) + ); - /** - * Set the amount of time to wait for a page load to complete before throwing - * an error. - * - * @param int $seconds Wait time in second. - * @return WebDriverTimeouts The current instance. - */ - public function pageLoadTimeout($seconds) { - $this->executor->execute(DriverCommand::SET_TIMEOUT, array( - 'type' => 'page load', - 'ms' => $seconds * 1000, - )); - return $this; - } + return $this; + } + + /** + * Set the amount of time to wait for a page load to complete before throwing + * an error. + * + * @param int $seconds Wait time in second. + * @return WebDriverTimeouts The current instance. + */ + public function pageLoadTimeout($seconds) + { + $this->executor->execute(DriverCommand::SET_TIMEOUT, array( + 'type' => 'page load', + 'ms' => $seconds * 1000, + )); + + return $this; + } } diff --git a/lib/WebDriverUpAction.php b/lib/WebDriverUpAction.php index 2394f41a1..e8a480c9e 100644 --- a/lib/WebDriverUpAction.php +++ b/lib/WebDriverUpAction.php @@ -18,25 +18,25 @@ use Facebook\WebDriver\Interactions\Touch\WebDriverTouchAction; use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen; -class WebDriverUpAction - extends WebDriverTouchAction - implements WebDriverAction { +class WebDriverUpAction extends WebDriverTouchAction implements WebDriverAction +{ + private $x; + private $y; - private $x; - private $y; + /** + * @param WebDriverTouchScreen $touch_screen + * @param int $x + * @param int $y + */ + public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) + { + $this->x = $x; + $this->y = $y; + parent::__construct($touch_screen); + } - /** - * @param WebDriverTouchScreen $touch_screen - * @param int $x - * @param int $y - */ - public function __construct(WebDriverTouchScreen $touch_screen, $x, $y) { - $this->x = $x; - $this->y = $y; - parent::__construct($touch_screen); - } - - public function perform() { - $this->touchScreen->up($this->x, $this->y); - } + public function perform() + { + $this->touchScreen->up($this->x, $this->y); + } } diff --git a/lib/WebDriverWait.php b/lib/WebDriverWait.php index 5cddd29c3..a2297779d 100644 --- a/lib/WebDriverWait.php +++ b/lib/WebDriverWait.php @@ -24,57 +24,56 @@ * * @see WebDriverExpectedCondition. */ -class WebDriverWait { +class WebDriverWait +{ + protected $driver; + protected $timeout; + protected $interval; - protected $driver; - protected $timeout; - protected $interval; - - public function __construct( - WebDriver $driver, - $timeout_in_second = null, - $interval_in_millisecond = null) { - $this->driver = $driver; - $this->timeout = isset($timeout_in_second) ? $timeout_in_second : 30; - $this->interval = $interval_in_millisecond ?: 250; - } - - /** - * Calls the function provided with the driver as an argument until the return - * value is not falsey. - * - * @param (closure|WebDriverExpectedCondition) - * @param string $message - * - * @return mixed The return value of $func_or_ec + public function __construct(WebDriver $driver, $timeout_in_second = null, $interval_in_millisecond = null) + { + $this->driver = $driver; + $this->timeout = isset($timeout_in_second) ? $timeout_in_second : 30; + $this->interval = $interval_in_millisecond ?: 250; + } - * @throws NoSuchElementException - * @throws TimeOutException - * @throws \Exception - */ - public function until($func_or_ec, $message = "") { - $end = microtime(true) + $this->timeout; - $last_exception = null; + /** + * Calls the function provided with the driver as an argument until the return + * value is not falsey. + * + * @param (closure|WebDriverExpectedCondition) + * @param string $message + * + * @throws NoSuchElementException + * @throws TimeOutException + * @throws \Exception + * @return mixed The return value of $func_or_ec + */ + public function until($func_or_ec, $message = '') + { + $end = microtime(true) + $this->timeout; + $last_exception = null; - while ($end > microtime(true)) { - try { - if ($func_or_ec instanceof WebDriverExpectedCondition) { - $ret_val = call_user_func($func_or_ec->getApply(), $this->driver); - } else { - $ret_val = call_user_func($func_or_ec, $this->driver); + while ($end > microtime(true)) { + try { + if ($func_or_ec instanceof WebDriverExpectedCondition) { + $ret_val = call_user_func($func_or_ec->getApply(), $this->driver); + } else { + $ret_val = call_user_func($func_or_ec, $this->driver); + } + if ($ret_val) { + return $ret_val; + } + } catch (NoSuchElementException $e) { + $last_exception = $e; + } + usleep($this->interval * 1000); } - if ($ret_val) { - return $ret_val; + + if ($last_exception) { + throw $last_exception; } - } catch (NoSuchElementException $e) { - $last_exception = $e; - } - usleep($this->interval * 1000); - } - if ($last_exception) { - throw $last_exception; + throw new TimeOutException($message); } - throw new TimeOutException($message); - } } diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index dcfa19534..b63a681b3 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -21,128 +21,138 @@ /** * An abstraction allowing the driver to manipulate the browser's window */ -class WebDriverWindow { - - protected $executor; - - public function __construct($executor) { - $this->executor = $executor; - } - - /** - * Get the position of the current window, relative to the upper left corner - * of the screen. - * - * @return array The current window position. - */ - public function getPosition() { - $position = $this->executor->execute( - DriverCommand::GET_WINDOW_POSITION, - array(':windowHandle' => 'current') - ); - return new WebDriverPoint( - $position['x'], - $position['y'] - ); - } - - /** - * Get the size of the current window. This will return the outer window - * dimension, not just the view port. - * - * @return array The current window size. - */ - public function getSize() { - $size = $this->executor->execute( - DriverCommand::GET_WINDOW_SIZE, - array(':windowHandle' => 'current') - ); - return new WebDriverDimension( - $size['width'], - $size['height'] - ); - } - - /** - * Maximizes the current window if it is not already maximized - * - * @return WebDriverWindow The instance. - */ - public function maximize() { - $this->executor->execute( - DriverCommand::MAXIMIZE_WINDOW, - array(':windowHandle' => 'current') - ); - return $this; - } - - /** - * Set the size of the current window. This will change the outer window - * dimension, not just the view port. - * - * @param WebDriverDimension $size - * @return WebDriverWindow The instance. - */ - public function setSize(WebDriverDimension $size) { - $params = array( - 'width' => $size->getWidth(), - 'height' => $size->getHeight(), - ':windowHandle' => 'current', - ); - $this->executor->execute(DriverCommand::SET_WINDOW_SIZE, $params); - return $this; - } - - /** - * Set the position of the current window. This is relative to the upper left - * corner of the screen. - * - * @param WebDriverPoint $position - * @return WebDriverWindow The instance. - */ - public function setPosition(WebDriverPoint $position) { - $params = array( - 'x' => $position->getX(), - 'y' => $position->getY(), - ':windowHandle' => 'current', - ); - $this->executor->execute(DriverCommand::SET_WINDOW_POSITION, $params); - return $this; - } - - /** - * Get the current browser orientation. - * - * @return string Either LANDSCAPE|PORTRAIT - */ - public function getScreenOrientation() { - return $this->executor->execute(DriverCommand::GET_SCREEN_ORIENTATION); - } - - - /** - * Set the browser orientation. The orientation should either - * LANDSCAPE|PORTRAIT - * - * @param string $orientation - * @return WebDriverWindow The instance. - * @throws IndexOutOfBoundsException - */ - public function setScreenOrientation($orientation) { - $orientation = strtoupper($orientation); - if (!in_array($orientation, array('PORTRAIT', 'LANDSCAPE'))) { - throw new IndexOutOfBoundsException( - "Orientation must be either PORTRAIT, or LANDSCAPE" - ); +class WebDriverWindow +{ + protected $executor; + + public function __construct($executor) + { + $this->executor = $executor; + } + + /** + * Get the position of the current window, relative to the upper left corner + * of the screen. + * + * @return array The current window position. + */ + public function getPosition() + { + $position = $this->executor->execute( + DriverCommand::GET_WINDOW_POSITION, + array(':windowHandle' => 'current') + ); + + return new WebDriverPoint( + $position['x'], + $position['y'] + ); } - $this->executor->execute( - DriverCommand::SET_SCREEN_ORIENTATION, - array('orientation' => $orientation) - ); + /** + * Get the size of the current window. This will return the outer window + * dimension, not just the view port. + * + * @return array The current window size. + */ + public function getSize() + { + $size = $this->executor->execute( + DriverCommand::GET_WINDOW_SIZE, + array(':windowHandle' => 'current') + ); + + return new WebDriverDimension( + $size['width'], + $size['height'] + ); + } - return $this; + /** + * Maximizes the current window if it is not already maximized + * + * @return WebDriverWindow The instance. + */ + public function maximize() + { + $this->executor->execute( + DriverCommand::MAXIMIZE_WINDOW, + array(':windowHandle' => 'current') + ); + + return $this; + } - } + /** + * Set the size of the current window. This will change the outer window + * dimension, not just the view port. + * + * @param WebDriverDimension $size + * @return WebDriverWindow The instance. + */ + public function setSize(WebDriverDimension $size) + { + $params = array( + 'width' => $size->getWidth(), + 'height' => $size->getHeight(), + ':windowHandle' => 'current', + ); + $this->executor->execute(DriverCommand::SET_WINDOW_SIZE, $params); + + return $this; + } + /** + * Set the position of the current window. This is relative to the upper left + * corner of the screen. + * + * @param WebDriverPoint $position + * @return WebDriverWindow The instance. + */ + public function setPosition(WebDriverPoint $position) + { + $params = array( + 'x' => $position->getX(), + 'y' => $position->getY(), + ':windowHandle' => 'current', + ); + $this->executor->execute(DriverCommand::SET_WINDOW_POSITION, $params); + + return $this; + } + + /** + * Get the current browser orientation. + * + * @return string Either LANDSCAPE|PORTRAIT + */ + public function getScreenOrientation() + { + return $this->executor->execute(DriverCommand::GET_SCREEN_ORIENTATION); + } + + /** + * Set the browser orientation. The orientation should either + * LANDSCAPE|PORTRAIT + * + * @param string $orientation + * @throws IndexOutOfBoundsException + * @return WebDriverWindow The instance. + */ + public function setScreenOrientation($orientation) + { + $orientation = strtoupper($orientation); + if (!in_array($orientation, array('PORTRAIT', 'LANDSCAPE'))) { + throw new IndexOutOfBoundsException( + 'Orientation must be either PORTRAIT, or LANDSCAPE' + ); + } + + $this->executor->execute( + DriverCommand::SET_SCREEN_ORIENTATION, + array('orientation' => $orientation) + ); + + return $this; + } } diff --git a/tests/functional/BaseTest.php b/tests/functional/BaseTest.php index 351db6ed2..c9c522651 100644 --- a/tests/functional/BaseTest.php +++ b/tests/functional/BaseTest.php @@ -15,85 +15,95 @@ namespace Facebook\WebDriver; -class BaseTest extends WebDriverTestCase { - - public function testGetTitle() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'php-webdriver test page', - $this->driver->getTitle() - ); - } - - public function testGetText() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Welcome to the facebook/php-webdriver testing page.', - $this->driver->findElement(WebDriverBy::id('welcome'))->getText() - ); - } +class BaseTest extends WebDriverTestCase +{ + public function testGetTitle() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'php-webdriver test page', + $this->driver->getTitle() + ); + } - public function testGetById() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Test by ID', - $this->driver->findElement(WebDriverBy::id('id_test'))->getText() - ); - } + public function testGetText() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Welcome to the facebook/php-webdriver testing page.', + $this->driver->findElement(WebDriverBy::id('welcome'))->getText() + ); + } - public function testGetByClassName() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Test by Class', - $this->driver->findElement(WebDriverBy::className('test_class'))->getText() - ); - } + public function testGetById() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Test by ID', + $this->driver->findElement(WebDriverBy::id('id_test'))->getText() + ); + } - public function testGetByCssSelector() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Test by Class', - $this->driver->findElement(WebDriverBy::cssSelector('.test_class'))->getText() - ); - } + public function testGetByClassName() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Test by Class', + $this->driver->findElement(WebDriverBy::className('test_class'))->getText() + ); + } - public function testGetByLinkText() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Click here', - $this->driver->findElement(WebDriverBy::linkText('Click here'))->getText() - ); - } + public function testGetByCssSelector() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Test by Class', + $this->driver->findElement(WebDriverBy::cssSelector('.test_class'))->getText() + ); + } - public function testGetByName() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Test Value', - $this->driver->findElement(WebDriverBy::name('test_name'))->getAttribute('value') - ); - } + public function testGetByLinkText() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Click here', + $this->driver->findElement(WebDriverBy::linkText('Click here'))->getText() + ); + } - public function testGetByXpath() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Test Value', - $this->driver->findElement(WebDriverBy::xpath('//input[@name="test_name"]'))->getAttribute('value') - ); - } + public function testGetByName() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Test Value', + $this->driver->findElement(WebDriverBy::name('test_name'))->getAttribute('value') + ); + } - public function testGetByPartialLinkText() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Click here', - $this->driver->findElement(WebDriverBy::partialLinkText('Click'))->getText() - ); - } + public function testGetByXpath() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Test Value', + $this->driver->findElement(WebDriverBy::xpath('//input[@name="test_name"]'))->getAttribute('value') + ); + } - public function testGetByTagName() { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'Test Value', - $this->driver->findElement(WebDriverBy::tagName('input'))->getAttribute('value') - ); - } + public function testGetByPartialLinkText() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Click here', + $this->driver->findElement(WebDriverBy::partialLinkText('Click'))->getText() + ); + } + + public function testGetByTagName() + { + $this->driver->get($this->getTestPath('index.html')); + self::assertEquals( + 'Test Value', + $this->driver->findElement(WebDriverBy::tagName('input'))->getAttribute('value') + ); + } } diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index 0ab233a14..29b878d9f 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -19,28 +19,31 @@ /** * An example test case for php-webdriver. - * - * Try running it by + * + * Try running it by * '../vendor/phpunit/phpunit/phpunit.php ExampleTestCase.php' */ -class FileUploadTest extends WebDriverTestCase { - - public function testFileUploading() { - $this->driver->get($this->getTestPath('upload.html')); - $file_input = $this->driver->findElement(WebDriverBy::id('upload')); - $file_input->setFileDetector(new LocalFileDetector()) - ->sendKeys(__DIR__ . '/files/FileUploadTestCaseFile.txt'); - self::assertNotEquals($this->getFilePath(), $file_input->getAttribute('value')); - } +class FileUploadTest extends WebDriverTestCase +{ + public function testFileUploading() + { + $this->driver->get($this->getTestPath('upload.html')); + $file_input = $this->driver->findElement(WebDriverBy::id('upload')); + $file_input->setFileDetector(new LocalFileDetector()) + ->sendKeys(__DIR__ . '/files/FileUploadTestCaseFile.txt'); + self::assertNotEquals($this->getFilePath(), $file_input->getAttribute('value')); + } - public function testUselessFileDetectorSendKeys() { - $this->driver->get($this->getTestPath('upload.html')); - $file_input = $this->driver->findElement(WebDriverBy::id('upload')); - $file_input->sendKeys($this->getFilePath()); - self::assertEquals($this->getFilePath(), $file_input->getAttribute('value')); - } - - private function getFilePath() { - return __DIR__ . '/files/FileUploadTestCaseFile.txt'; - } + public function testUselessFileDetectorSendKeys() + { + $this->driver->get($this->getTestPath('upload.html')); + $file_input = $this->driver->findElement(WebDriverBy::id('upload')); + $file_input->sendKeys($this->getFilePath()); + self::assertEquals($this->getFilePath(), $file_input->getAttribute('value')); + } + + private function getFilePath() + { + return __DIR__ . '/files/FileUploadTestCaseFile.txt'; + } } diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 9be2153d3..fca694854 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -22,35 +22,38 @@ /** * The base class for test cases. */ -class WebDriverTestCase extends \PHPUnit_Framework_TestCase { +class WebDriverTestCase extends \PHPUnit_Framework_TestCase +{ + /** @var RemoteWebDriver $driver */ + protected $driver; - /** @var RemoteWebDriver $driver */ - protected $driver; + protected function setUp() + { + $this->driver = RemoteWebDriver::create( + 'http://localhost:4444/wd/hub', + array( + WebDriverCapabilityType::BROWSER_NAME + //=> WebDriverBrowserType::FIREFOX, + => WebDriverBrowserType::HTMLUNIT, + ) + ); + } - protected function setUp() { - $this->driver = RemoteWebDriver::create( - 'http://localhost:4444/wd/hub', - array( - WebDriverCapabilityType::BROWSER_NAME - //=> WebDriverBrowserType::FIREFOX, - => WebDriverBrowserType::HTMLUNIT, - ) - ); - } - - protected function tearDown() { - if ($this->driver) { - $this->driver->quit(); + protected function tearDown() + { + if ($this->driver) { + $this->driver->quit(); + } } - } - /** - * Get the URL of the test html. - * - * @param $path - * @return string - */ - protected function getTestPath($path) { - return 'file:///'.__DIR__.'/html/'.$path; - } + /** + * Get the URL of the test html. + * + * @param $path + * @return string + */ + protected function getTestPath($path) + { + return 'file:///' . __DIR__ . '/html/' . $path; + } } diff --git a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php index 58373d9b9..a192190f9 100644 --- a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php @@ -18,28 +18,31 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverButtonReleaseActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverButtonReleaseAction */ - private $webDriverButtonReleaseAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverButtonReleaseActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverButtonReleaseAction */ + private $webDriverButtonReleaseAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverButtonReleaseAction = new WebDriverButtonReleaseAction( - $this->webDriverMouse, - $this->locationProvider - ); - } + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverButtonReleaseAction = new WebDriverButtonReleaseAction( + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformSendsMouseUpCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('mouseUp')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverButtonReleaseAction->perform(); - } + public function testPerformSendsMouseUpCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('mouseUp')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverButtonReleaseAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php index c58d507d1..62162c77e 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php @@ -18,28 +18,31 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverClickActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverClickAction */ - private $webDriverClickAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverClickActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverClickAction */ + private $webDriverClickAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverClickAction = new WebDriverClickAction( - $this->webDriverMouse, - $this->locationProvider - ); - } + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverClickAction = new WebDriverClickAction( + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformSendsClickCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('click')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverClickAction->perform(); - } + public function testPerformSendsClickCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('click')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverClickAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php index ae046c58e..9dec8b9aa 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php @@ -18,28 +18,31 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverClickAndHoldActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverClickAndHoldAction */ - private $webDriverClickAndHoldAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverClickAndHoldActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverClickAndHoldAction */ + private $webDriverClickAndHoldAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverClickAndHoldAction = new WebDriverClickAndHoldAction( - $this->webDriverMouse, - $this->locationProvider - ); - } + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverClickAndHoldAction = new WebDriverClickAndHoldAction( + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformSendsMouseDownCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('mouseDown')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverClickAndHoldAction->perform(); - } + public function testPerformSendsMouseDownCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('mouseDown')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverClickAndHoldAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php index d9b9ef2b8..2c5a92547 100644 --- a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php @@ -18,28 +18,31 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverContextClickActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverContextClickAction */ - private $webDriverContextClickAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverContextClickActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverContextClickAction */ + private $webDriverContextClickAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverContextClickAction = new WebDriverContextClickAction( - $this->webDriverMouse, - $this->locationProvider - ); - } + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverContextClickAction = new WebDriverContextClickAction( + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformSendsContextClickCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('contextClick')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverContextClickAction->perform(); - } + public function testPerformSendsContextClickCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('contextClick')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverContextClickAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php b/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php index d38c7220a..d782edf8c 100644 --- a/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php +++ b/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php @@ -15,26 +15,32 @@ namespace Facebook\WebDriver\Interactions\Internal; -class WebDriverCoordinatesTest extends \PHPUnit_Framework_TestCase { - public function testConstruct() { - $in_view_port = function() { }; - $on_page = function() { }; +class WebDriverCoordinatesTest extends \PHPUnit_Framework_TestCase +{ + public function testConstruct() + { + $in_view_port = function () { + }; + $on_page = function () { + }; - $webDriverCoordinates = new WebDriverCoordinates(null, $in_view_port, $on_page, 'auxiliary'); + $webDriverCoordinates = new WebDriverCoordinates(null, $in_view_port, $on_page, 'auxiliary'); - self::assertAttributeEquals(null, 'onScreen', $webDriverCoordinates); - self::assertAttributeEquals($in_view_port, 'inViewPort', $webDriverCoordinates); - self::assertAttributeEquals($on_page, 'onPage', $webDriverCoordinates); - self::assertAttributeEquals('auxiliary', 'auxiliary', $webDriverCoordinates); - } + self::assertAttributeEquals(null, 'onScreen', $webDriverCoordinates); + self::assertAttributeEquals($in_view_port, 'inViewPort', $webDriverCoordinates); + self::assertAttributeEquals($on_page, 'onPage', $webDriverCoordinates); + self::assertAttributeEquals('auxiliary', 'auxiliary', $webDriverCoordinates); + } - public function testGetAuxiliary() - { - $in_view_port = function() { }; - $on_page = function() { }; + public function testGetAuxiliary() + { + $in_view_port = function () { + }; + $on_page = function () { + }; - $webDriverCoordinates = new WebDriverCoordinates(null, $in_view_port, $on_page, 'auxiliary'); + $webDriverCoordinates = new WebDriverCoordinates(null, $in_view_port, $on_page, 'auxiliary'); - self::assertEquals('auxiliary', $webDriverCoordinates->getAuxiliary()); - } + self::assertEquals('auxiliary', $webDriverCoordinates->getAuxiliary()); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php index f1c6d3a02..b83115f77 100644 --- a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php @@ -18,28 +18,31 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverDoubleClickActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverDoubleClickAction */ - private $webDriverDoubleClickAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverDoubleClickActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverDoubleClickAction */ + private $webDriverDoubleClickAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverDoubleClickAction = new WebDriverDoubleClickAction( - $this->webDriverMouse, - $this->locationProvider - ); - } + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverDoubleClickAction = new WebDriverDoubleClickAction( + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformSendsDoubleClickCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('doubleClick')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverDoubleClickAction->perform(); - } + public function testPerformSendsDoubleClickCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('doubleClick')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverDoubleClickAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php index 10a6201e0..e1cb8acbc 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php @@ -19,34 +19,37 @@ use Facebook\WebDriver\WebDriverKeyboard; use Facebook\WebDriver\WebDriverMouse; -class WebDriverKeyDownActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverKeyDownAction */ - private $webDriverKeyDownAction; - /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverKeyboard; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverKeyDownActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverKeyDownAction */ + private $webDriverKeyDownAction; + /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverKeyboard; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + public function setUp() + { + $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverKeyDownAction = new WebDriverKeyDownAction( - $this->webDriverKeyboard, - $this->webDriverMouse, - $this->locationProvider - ); - } + $this->webDriverKeyDownAction = new WebDriverKeyDownAction( + $this->webDriverKeyboard, + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('click')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverKeyboard->expects($this->once())->method('pressKey'); - $this->webDriverKeyDownAction->perform(); - } + public function testPerformFocusesOnElementAndSendPressKeyCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('click')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverKeyboard->expects($this->once())->method('pressKey'); + $this->webDriverKeyDownAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php index 75fb1bde9..c21ac24c1 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php @@ -19,35 +19,38 @@ use Facebook\WebDriver\WebDriverKeyboard; use Facebook\WebDriver\WebDriverMouse; -class WebDriverKeyUpActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverKeyUpAction */ - private $webDriverKeyUpAction; - /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverKeyboard; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverKeyUpActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverKeyUpAction */ + private $webDriverKeyUpAction; + /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverKeyboard; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + public function setUp() + { + $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverKeyUpAction = new WebDriverKeyUpAction( - $this->webDriverKeyboard, - $this->webDriverMouse, - $this->locationProvider, - 'a' - ); - } + $this->webDriverKeyUpAction = new WebDriverKeyUpAction( + $this->webDriverKeyboard, + $this->webDriverMouse, + $this->locationProvider, + 'a' + ); + } - public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('click')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverKeyboard->expects($this->once())->method('releaseKey')->with('a'); - $this->webDriverKeyUpAction->perform(); - } + public function testPerformFocusesOnElementAndSendPressKeyCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('click')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverKeyboard->expects($this->once())->method('releaseKey')->with('a'); + $this->webDriverKeyUpAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php index 10edb2588..fe3ca9379 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php @@ -18,29 +18,32 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverMouseMoveActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverMouseMoveAction */ - private $webDriverMouseMoveAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverMouseMoveActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverMouseMoveAction */ + private $webDriverMouseMoveAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverMouseMoveAction = new WebDriverMouseMoveAction( - $this->webDriverMouse, - $this->locationProvider - ); - } + $this->webDriverMouseMoveAction = new WebDriverMouseMoveAction( + $this->webDriverMouse, + $this->locationProvider + ); + } - public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('mouseMove')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverMouseMoveAction->perform(); - } + public function testPerformFocusesOnElementAndSendPressKeyCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('mouseMove')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverMouseMoveAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php index aeec43a5a..37a2853ba 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php @@ -18,33 +18,36 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; -class WebDriverMouseToOffsetActionTest extends \PHPUnit_Framework_TestCase { - /** - * @type WebDriverMoveToOffsetAction - */ - private $webDriverMoveToOffsetAction; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; +class WebDriverMouseToOffsetActionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @type WebDriverMoveToOffsetAction + */ + private $webDriverMoveToOffsetAction; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; - public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + public function setUp() + { + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->webDriverMoveToOffsetAction = new WebDriverMoveToOffsetAction( - $this->webDriverMouse, - $this->locationProvider, - 150, - 200 - ); - } + $this->webDriverMoveToOffsetAction = new WebDriverMoveToOffsetAction( + $this->webDriverMouse, + $this->locationProvider, + 150, + 200 + ); + } - public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverMouse->expects($this->once())->method('mouseMove')->with($coords, 150, 200); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverMoveToOffsetAction->perform(); - } + public function testPerformFocusesOnElementAndSendPressKeyCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverMouse->expects($this->once())->method('mouseMove')->with($coords, 150, 200); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverMoveToOffsetAction->perform(); + } } diff --git a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php index bf1a5b8a7..82a736dea 100644 --- a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php @@ -19,38 +19,41 @@ use Facebook\WebDriver\WebDriverKeyboard; use Facebook\WebDriver\WebDriverMouse; -class WebDriverSendKeysActionTest extends \PHPUnit_Framework_TestCase { - /** @var WebDriverSendKeysAction */ - private $webDriverSendKeysAction; - /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverKeyboard; - /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ - private $webDriverMouse; - /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ - private $locationProvider; - /** @var array */ - private $keys; +class WebDriverSendKeysActionTest extends \PHPUnit_Framework_TestCase +{ + /** @var WebDriverSendKeysAction */ + private $webDriverSendKeysAction; + /** @var WebDriverKeyboard|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverKeyboard; + /** @var WebDriverMouse|\PHPUnit_Framework_MockObject_MockObject */ + private $webDriverMouse; + /** @var WebDriverLocatable|\PHPUnit_Framework_MockObject_MockObject */ + private $locationProvider; + /** @var array */ + private $keys; - public function setUp() { - $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + public function setUp() + { + $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); + $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); + $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); - $this->keys = array('t', 'e', 's', 't'); - $this->webDriverSendKeysAction = new WebDriverSendKeysAction( - $this->webDriverKeyboard, - $this->webDriverMouse, - $this->locationProvider, - $this->keys - ); - } + $this->keys = array('t', 'e', 's', 't'); + $this->webDriverSendKeysAction = new WebDriverSendKeysAction( + $this->webDriverKeyboard, + $this->webDriverMouse, + $this->locationProvider, + $this->keys + ); + } - public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') - ->disableOriginalConstructor()->getMock(); - $this->webDriverKeyboard->expects($this->once())->method('sendKeys')->with($this->keys); - $this->webDriverMouse->expects($this->once())->method('click')->with($coords); - $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); - $this->webDriverSendKeysAction->perform(); - } + public function testPerformFocusesOnElementAndSendPressKeyCommand() + { + $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + ->disableOriginalConstructor()->getMock(); + $this->webDriverKeyboard->expects($this->once())->method('sendKeys')->with($this->keys); + $this->webDriverMouse->expects($this->once())->method('click')->with($coords); + $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); + $this->webDriverSendKeysAction->perform(); + } } diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index 7f187f706..54f17a14d 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -22,112 +22,111 @@ class DesiredCapabilitiesTest extends \PHPUnit_Framework_TestCase { - public function testShouldInstantiateWithCapabilitiesGivenInConstructor() - { - $capabilities = new DesiredCapabilities( - array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY) - ); - - $this->assertSame('fooVal', $capabilities->getCapability('fooKey')); - $this->assertSame('ANY', $capabilities->getPlatform()); - - $this->assertSame( - array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY), - $capabilities->toArray() - ); - } - - public function testShouldInstantiateEmptyInstance() - { - $capabilities = new DesiredCapabilities(); - - $this->assertNull($capabilities->getCapability('foo')); - $this->assertSame(array(), $capabilities->toArray()); - } - - public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() - { - $capabilities = new DesiredCapabilities(); - // generic capability setter - $capabilities->setCapability('custom', 1337); - // specific setters - $capabilities->setBrowserName(WebDriverBrowserType::CHROME); - $capabilities->setPlatform(WebDriverPlatform::LINUX); - $capabilities->setVersion(333); - - $this->assertSame(1337, $capabilities->getCapability('custom')); - $this->assertSame(WebDriverBrowserType::CHROME, $capabilities->getBrowserName()); - $this->assertSame(WebDriverPlatform::LINUX, $capabilities->getPlatform()); - $this->assertSame(333, $capabilities->getVersion()); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage isJavascriptEnable() is a htmlunit-only option - */ - public function testShouldNotAllowToDisableJavascriptForNonHtmlUnitBrowser() - { - $capabilities = new DesiredCapabilities(); - $capabilities->setBrowserName(WebDriverBrowserType::FIREFOX); - $capabilities->setJavascriptEnabled(false); - } - - public function testShouldAllowToDisableJavascriptForHtmlUnitBrowser() - { - $capabilities = new DesiredCapabilities(); - $capabilities->setBrowserName(WebDriverBrowserType::HTMLUNIT); - $capabilities->setJavascriptEnabled(false); - - $this->assertFalse($capabilities->isJavascriptEnabled()); - } - - /** - * @dataProvider browserCapabilitiesProvider - * @param string $setupMethod - * @param string $expectedBrowser - * @param string $expectedPlatform - */ - public function testShouldProvideShortcutSetupForCapabilitiesOfEachBrowser( - $setupMethod, - $expectedBrowser, - $expectedPlatform - ) - { - /** @var DesiredCapabilities $capabilities */ - $capabilities = call_user_func(array('Facebook\WebDriver\Remote\DesiredCapabilities', $setupMethod)); - - $this->assertSame($expectedBrowser, $capabilities->getBrowserName()); - $this->assertSame($expectedPlatform, $capabilities->getPlatform()); - } - - /** - * @return array - */ - public function browserCapabilitiesProvider() - { - return array( - array('android', WebDriverBrowserType::ANDROID, WebDriverPlatform::ANDROID), - array('chrome', WebDriverBrowserType::CHROME, WebDriverPlatform::ANY), - array('firefox', WebDriverBrowserType::FIREFOX, WebDriverPlatform::ANY), - array('htmlUnit', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), - array('htmlUnitWithJS', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), - array('internetExplorer', WebDriverBrowserType::IE, WebDriverPlatform::WINDOWS), - array('iphone', WebDriverBrowserType::IPHONE, WebDriverPlatform::MAC), - array('ipad', WebDriverBrowserType::IPAD, WebDriverPlatform::MAC), - array('opera', WebDriverBrowserType::OPERA, WebDriverPlatform::ANY), - array('safari', WebDriverBrowserType::SAFARI, WebDriverPlatform::ANY), - array('phantomjs', WebDriverBrowserType::PHANTOMJS, WebDriverPlatform::ANY), - ); - } - - public function testShouldSetupFirefoxProfileAndDisableReaderViewForFirefoxBrowser() - { - $capabilities = DesiredCapabilities::firefox(); - - /** @var FirefoxProfile $firefoxProfile */ - $firefoxProfile = $capabilities->getCapability(FirefoxDriver::PROFILE); - $this->assertInstanceOf('Facebook\WebDriver\Firefox\FirefoxProfile', $firefoxProfile); - - $this->assertSame('false', $firefoxProfile->getPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED)); - } + public function testShouldInstantiateWithCapabilitiesGivenInConstructor() + { + $capabilities = new DesiredCapabilities( + array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY) + ); + + $this->assertSame('fooVal', $capabilities->getCapability('fooKey')); + $this->assertSame('ANY', $capabilities->getPlatform()); + + $this->assertSame( + array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY), + $capabilities->toArray() + ); + } + + public function testShouldInstantiateEmptyInstance() + { + $capabilities = new DesiredCapabilities(); + + $this->assertNull($capabilities->getCapability('foo')); + $this->assertSame(array(), $capabilities->toArray()); + } + + public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() + { + $capabilities = new DesiredCapabilities(); + // generic capability setter + $capabilities->setCapability('custom', 1337); + // specific setters + $capabilities->setBrowserName(WebDriverBrowserType::CHROME); + $capabilities->setPlatform(WebDriverPlatform::LINUX); + $capabilities->setVersion(333); + + $this->assertSame(1337, $capabilities->getCapability('custom')); + $this->assertSame(WebDriverBrowserType::CHROME, $capabilities->getBrowserName()); + $this->assertSame(WebDriverPlatform::LINUX, $capabilities->getPlatform()); + $this->assertSame(333, $capabilities->getVersion()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage isJavascriptEnable() is a htmlunit-only option + */ + public function testShouldNotAllowToDisableJavascriptForNonHtmlUnitBrowser() + { + $capabilities = new DesiredCapabilities(); + $capabilities->setBrowserName(WebDriverBrowserType::FIREFOX); + $capabilities->setJavascriptEnabled(false); + } + + public function testShouldAllowToDisableJavascriptForHtmlUnitBrowser() + { + $capabilities = new DesiredCapabilities(); + $capabilities->setBrowserName(WebDriverBrowserType::HTMLUNIT); + $capabilities->setJavascriptEnabled(false); + + $this->assertFalse($capabilities->isJavascriptEnabled()); + } + + /** + * @dataProvider browserCapabilitiesProvider + * @param string $setupMethod + * @param string $expectedBrowser + * @param string $expectedPlatform + */ + public function testShouldProvideShortcutSetupForCapabilitiesOfEachBrowser( + $setupMethod, + $expectedBrowser, + $expectedPlatform + ) { + /** @var DesiredCapabilities $capabilities */ + $capabilities = call_user_func(array('Facebook\WebDriver\Remote\DesiredCapabilities', $setupMethod)); + + $this->assertSame($expectedBrowser, $capabilities->getBrowserName()); + $this->assertSame($expectedPlatform, $capabilities->getPlatform()); + } + + /** + * @return array + */ + public function browserCapabilitiesProvider() + { + return array( + array('android', WebDriverBrowserType::ANDROID, WebDriverPlatform::ANDROID), + array('chrome', WebDriverBrowserType::CHROME, WebDriverPlatform::ANY), + array('firefox', WebDriverBrowserType::FIREFOX, WebDriverPlatform::ANY), + array('htmlUnit', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), + array('htmlUnitWithJS', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), + array('internetExplorer', WebDriverBrowserType::IE, WebDriverPlatform::WINDOWS), + array('iphone', WebDriverBrowserType::IPHONE, WebDriverPlatform::MAC), + array('ipad', WebDriverBrowserType::IPAD, WebDriverPlatform::MAC), + array('opera', WebDriverBrowserType::OPERA, WebDriverPlatform::ANY), + array('safari', WebDriverBrowserType::SAFARI, WebDriverPlatform::ANY), + array('phantomjs', WebDriverBrowserType::PHANTOMJS, WebDriverPlatform::ANY), + ); + } + + public function testShouldSetupFirefoxProfileAndDisableReaderViewForFirefoxBrowser() + { + $capabilities = DesiredCapabilities::firefox(); + + /** @var FirefoxProfile $firefoxProfile */ + $firefoxProfile = $capabilities->getCapability(FirefoxDriver::PROFILE); + $this->assertInstanceOf('Facebook\WebDriver\Firefox\FirefoxProfile', $firefoxProfile); + + $this->assertSame('false', $firefoxProfile->getPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED)); + } } diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php index b4b9fc052..c315b4b46 100644 --- a/tests/unit/Remote/WebDriverCommandTest.php +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -17,12 +17,12 @@ class WebDriverCommandTest extends \PHPUnit_Framework_TestCase { - public function testShouldSetOptionsUsingConstructot() - { - $command = new WebDriverCommand('session-id-123', 'bar-baz-name', array('foo' => 'bar')); + public function testShouldSetOptionsUsingConstructot() + { + $command = new WebDriverCommand('session-id-123', 'bar-baz-name', array('foo' => 'bar')); - $this->assertSame('session-id-123', $command->getSessionID()); - $this->assertSame('bar-baz-name', $command->getName()); - $this->assertSame(array('foo' => 'bar'), $command->getParameters()); - } + $this->assertSame('session-id-123', $command->getSessionID()); + $this->assertSame('bar-baz-name', $command->getName()); + $this->assertSame(array('foo' => 'bar'), $command->getParameters()); + } } From c8d18c6a6a214225aee6724c6a2f955cce163bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 30 Jul 2016 16:19:22 +0200 Subject: [PATCH 034/600] Check codestyle on Travis --- .gitignore | 3 ++- .php_cs | 41 +++++++++++++++++++++++++++++++++++++++++ .travis.yml | 25 +++++++++++++++++-------- composer.json | 4 +++- 4 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 .php_cs diff --git a/.gitignore b/.gitignore index 88ca8c5ff..2444076bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ composer.phar composer.lock vendor +.php_cs.cache # generic files to ignore *.lock *.DS_Store *~ *.swp -.idea \ No newline at end of file +.idea diff --git a/.php_cs b/.php_cs new file mode 100644 index 000000000..752fb9606 --- /dev/null +++ b/.php_cs @@ -0,0 +1,41 @@ +in(array(__DIR__ . '/lib', __DIR__ . '/tests')); + +return Symfony\CS\Config\Config::create() + ->fixers(array( + 'duplicate_semicolon', + 'extra_empty_lines', + 'multiline_array_trailing_comma', + 'namespace_no_leading_whitespace', + 'new_with_braces', + 'no_blank_lines_after_class_opening', + 'no_empty_lines_after_phpdocs', + 'object_operator', + 'operators_spaces', + 'trim_array_spaces', + 'phpdoc_indent', + 'phpdoc_no_access', + 'phpdoc_no_empty_return', + 'phpdoc_no_package', + 'phpdoc_scalar', + 'phpdoc_trim', + 'phpdoc_types', + 'phpdoc_order', + 'unused_use', + 'ordered_use', + 'remove_leading_slash_use', + 'remove_lines_between_uses', + 'function_typehint_space', + 'self_accessor', + 'single_array_no_trailing_comma', + 'single_blank_line_before_namespace', + 'single_quote', + 'spaces_cast', + 'whitespacy_lines', + 'newline_after_open_tag', + )) + ->level(Symfony\CS\FixerInterface::PSR2_LEVEL) + ->setUsingCache(true) + ->finder($finder); diff --git a/.travis.yml b/.travis.yml index 20d852e96..eb8e94685 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,12 @@ php: - 7 - hhvm +matrix: + include: + # Add PHP 7 build to check codestyle only in PHP 7 build + - php: 7 + env: CHECK_CODESTYLE=1 + env: global: - DISPLAY=:99.0 @@ -19,18 +25,21 @@ cache: - $HOME/.composer/cache before_install: - - composer self-update + - travis_retry composer self-update install: - - composer install --no-interaction --prefer-source + - travis_retry composer install --no-interaction --prefer-source before_script: - - sh -e /etc/init.d/xvfb start - - wget -q -t 3 http://selenium-release.storage.googleapis.com/2.45/selenium-server-standalone-2.45.0.jar - - java -jar selenium-server-standalone-2.45.0.jar -log selenium.log & - - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done; - -script: ./vendor/bin/phpunit + - if [ -z "$CHECK_CODESTYLE" ]; then sh -e /etc/init.d/xvfb start; fi + - if [ -z "$CHECK_CODESTYLE" ]; then wget -q -t 3 http://selenium-release.storage.googleapis.com/2.45/selenium-server-standalone-2.45.0.jar; fi + - if [ -z "$CHECK_CODESTYLE" ]; then java -jar selenium-server-standalone-2.45.0.jar -log selenium.log; fi & + - if [ -z "$CHECK_CODESTYLE" ]; then until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done; fi + +script: + - if [ -n "$CHECK_CODESTYLE" ]; then ./vendor/bin/php-cs-fixer fix --diff --dry-run; fi + - if [ -n "$CHECK_CODESTYLE" ]; then ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/; fi + - if [ -z "$CHECK_CODESTYLE" ]; then ./vendor/bin/phpunit; fi after_script: - cat selenium.log diff --git a/composer.json b/composer.json index 43c61fa88..227542bf1 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,9 @@ "ext-curl": "*" }, "require-dev": { - "phpunit/phpunit": "4.6.* || ~5.0" + "phpunit/phpunit": "4.6.* || ~5.0", + "friendsofphp/php-cs-fixer": "^1.11", + "squizlabs/php_codesniffer": "^2.6" }, "suggest": { "phpdocumentor/phpdocumentor": "2.*" From 642b5e4d2348d3f79080a62be1d8ce44af8fbe6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 30 Jul 2016 16:41:07 +0200 Subject: [PATCH 035/600] Update contributor info with code-style requirements --- CONTRIBUTING.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b426d475d..2abd92165 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ send a pull request (see bellow) with your contribution. 1. Fork the project on GitHub 2. Implement your code changes into separate branch -3. Make sure all PHPUnit tests passes (see below). We also have Travis CI build which will automatically run tests on your pull request). +3. Make sure all PHPUnit tests passes and code-style matches PSR-2 (see below). We also have Travis CI build which will automatically run tests on your pull request. 4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md) 5. Submit your [pull request](https://github.com/facebook/php-webdriver/pulls) against community branch @@ -34,3 +34,10 @@ For the functional tests you must first download and start the selenium server, java -jar selenium-server-standalone-2.48.2.jar -log selenium.log & ./vendor/bin/phpunit --testsuite functional + +### Check coding style + +Your code-style should comply with [PSR-2](http://www.php-fig.org/psr/psr-2/). To make sure your code matches this requirement run: + + ./vendor/bin/php-cs-fixer fix --diff --dry-run + ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/ From 8dd44ed56e4c61f308597486c47268a7574407de Mon Sep 17 00:00:00 2001 From: Michael Rijsdijk Date: Wed, 3 Aug 2016 14:06:12 +0200 Subject: [PATCH 036/600] Edit the link to the official Java API The link to the official Java API was broken --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b426d475d..a6125e2b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ send a pull request (see bellow) with your contribution. Note before any pull request can be accepted, a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed. When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. -FYI, here is the overview of [the official Java API](http://selenium.googlecode.com/svn/trunk/docs/api/java/index.html?overview-summary.html) +FYI, here is the overview of [the official Java API](http://seleniumhq.github.io/selenium/docs/api/java/) ### Run unit tests From 8606656ea824e535d56de3582ddec532a552cb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 2 Aug 2016 00:57:34 +0200 Subject: [PATCH 037/600] Add MicrosoftEdge to known browser types to enable basic Edge support (see #244) --- lib/Remote/DesiredCapabilities.php | 11 +++++++++++ lib/Remote/WebDriverBrowserType.php | 1 + tests/unit/Remote/DesiredCapabilitiesTest.php | 1 + 3 files changed, 13 insertions(+) diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 8e30aae14..9366a0293 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -271,6 +271,17 @@ public static function internetExplorer() )); } + /** + * @return DesiredCapabilities + */ + public static function microsoftEdge() + { + return new self(array( + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE, + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, + )); + } + /** * @return DesiredCapabilities */ diff --git a/lib/Remote/WebDriverBrowserType.php b/lib/Remote/WebDriverBrowserType.php index 977662a4a..4aa38125c 100644 --- a/lib/Remote/WebDriverBrowserType.php +++ b/lib/Remote/WebDriverBrowserType.php @@ -28,6 +28,7 @@ class WebDriverBrowserType const GOOGLECHROME = 'googlechrome'; const SAFARI = 'safari'; const OPERA = 'opera'; + const MICROSOFT_EDGE = 'MicrosoftEdge'; const IEXPLORE = 'iexplore'; const IEXPLORE_PROXY = 'iexploreproxy'; const SAFARI_PROXY = 'safariproxy'; diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index 54f17a14d..c68a747ed 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -110,6 +110,7 @@ public function browserCapabilitiesProvider() array('firefox', WebDriverBrowserType::FIREFOX, WebDriverPlatform::ANY), array('htmlUnit', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), array('htmlUnitWithJS', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), + array('MicrosoftEdge', WebDriverBrowserType::MICROSOFT_EDGE, WebDriverPlatform::WINDOWS), array('internetExplorer', WebDriverBrowserType::IE, WebDriverPlatform::WINDOWS), array('iphone', WebDriverBrowserType::IPHONE, WebDriverPlatform::MAC), array('ipad', WebDriverBrowserType::IPAD, WebDriverPlatform::MAC), From 5b3fdbe2fef3e3cba60d1d11904a487c67c0c22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 18 Aug 2016 20:23:18 +0200 Subject: [PATCH 038/600] Remove deprecated browser types --- lib/Remote/WebDriverBrowserType.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Remote/WebDriverBrowserType.php b/lib/Remote/WebDriverBrowserType.php index 4aa38125c..5dd61505e 100644 --- a/lib/Remote/WebDriverBrowserType.php +++ b/lib/Remote/WebDriverBrowserType.php @@ -21,17 +21,15 @@ class WebDriverBrowserType { const FIREFOX = 'firefox'; - const FIREFOX_2 = 'firefox2'; - const FIREFOX_3 = 'firefox3'; const FIREFOX_PROXY = 'firefoxproxy'; const FIREFOX_CHROME = 'firefoxchrome'; const GOOGLECHROME = 'googlechrome'; const SAFARI = 'safari'; + const SAFARI_PROXY = 'safariproxy'; const OPERA = 'opera'; const MICROSOFT_EDGE = 'MicrosoftEdge'; const IEXPLORE = 'iexplore'; const IEXPLORE_PROXY = 'iexploreproxy'; - const SAFARI_PROXY = 'safariproxy'; const CHROME = 'chrome'; const KONQUEROR = 'konqueror'; const MOCK = 'mock'; From 78582b90b721861bce6f90c2762d64a02c8fb51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 26 Aug 2016 00:31:32 +0200 Subject: [PATCH 039/600] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f379bdaa7..b24bc9bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- Added initial basic support of Microsoft Edge browser + +## 1.1.3 - 2016-08-10 - Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file - Comply codestyle with [PSR-2](http://www.php-fig.org/psr/psr-2/) From b9cd2ad25331566d5f9957e279ac31bb3ba56a2d Mon Sep 17 00:00:00 2001 From: Ivan Sebastian Date: Wed, 14 Sep 2016 09:04:02 +0700 Subject: [PATCH 040/600] Modify README to add link to sample code --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 146d45ad6..6cdae5742 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ $driver = RemoteWebDriver::create($host, $desired_capabilities); * See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities for more details. +* Above snippets are not intended to be a working example by simply copy pasting. See [example.php](example.php) for working example. + ## Changelog For latest changes see [CHANGELOG.md](CHANGELOG.md) file. From af4294ce7d703d39860a98d8a4c8545d62466580 Mon Sep 17 00:00:00 2001 From: Phelipe Alves de Souza Date: Fri, 16 Sep 2016 18:54:23 -0300 Subject: [PATCH 041/600] Declared not found fields --- lib/Interactions/Touch/WebDriverFlickAction.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Interactions/Touch/WebDriverFlickAction.php b/lib/Interactions/Touch/WebDriverFlickAction.php index 48e65dc95..52f43fde6 100644 --- a/lib/Interactions/Touch/WebDriverFlickAction.php +++ b/lib/Interactions/Touch/WebDriverFlickAction.php @@ -19,6 +19,9 @@ class WebDriverFlickAction extends WebDriverTouchAction implements WebDriverAction { + private $x; + private $y; + /** * @param WebDriverTouchScreen $touch_screen * @param int $x From 3ab0f89954a5bae784f3c4dab2cc57624bba7ba8 Mon Sep 17 00:00:00 2001 From: Sepehr Lajevardi Date: Tue, 20 Sep 2016 00:49:47 +0430 Subject: [PATCH 042/600] Fix typo in test method name. --- tests/unit/Remote/WebDriverCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php index c315b4b46..30a206119 100644 --- a/tests/unit/Remote/WebDriverCommandTest.php +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -17,7 +17,7 @@ class WebDriverCommandTest extends \PHPUnit_Framework_TestCase { - public function testShouldSetOptionsUsingConstructot() + public function testShouldSetOptionsUsingConstructor() { $command = new WebDriverCommand('session-id-123', 'bar-baz-name', array('foo' => 'bar')); From 25eeb6a1f2b99a85a8b79c6418e2453cd82a9f3e Mon Sep 17 00:00:00 2001 From: Sepehr Lajevardi Date: Wed, 5 Oct 2016 10:09:03 +0330 Subject: [PATCH 043/600] Utilize late static binding. --- lib/Chrome/ChromeDriverService.php | 2 +- lib/Remote/DesiredCapabilities.php | 24 ++++++++++---------- lib/WebDriverBy.php | 16 ++++++------- lib/WebDriverExpectedCondition.php | 36 +++++++++++++++--------------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/Chrome/ChromeDriverService.php b/lib/Chrome/ChromeDriverService.php index a48207a46..4fb3b59e5 100644 --- a/lib/Chrome/ChromeDriverService.php +++ b/lib/Chrome/ChromeDriverService.php @@ -27,7 +27,7 @@ public static function createDefaultService() $exe = getenv(self::CHROME_DRIVER_EXE_PROPERTY); $port = 9515; // TODO: Get another port if the default port is used. $args = array("--port=$port"); - $service = new self($exe, $port, $args); + $service = new static($exe, $port, $args); return $service; } diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 9366a0293..2a132b576 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -201,7 +201,7 @@ private function get($key, $default = null) */ public static function android() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID, )); @@ -212,7 +212,7 @@ public static function android() */ public static function chrome() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); @@ -223,7 +223,7 @@ public static function chrome() */ public static function firefox() { - $caps = new self(array( + $caps = new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); @@ -241,7 +241,7 @@ public static function firefox() */ public static function htmlUnit() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); @@ -252,7 +252,7 @@ public static function htmlUnit() */ public static function htmlUnitWithJS() { - $caps = new self(array( + $caps = new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); @@ -265,7 +265,7 @@ public static function htmlUnitWithJS() */ public static function internetExplorer() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, )); @@ -276,7 +276,7 @@ public static function internetExplorer() */ public static function microsoftEdge() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, )); @@ -287,7 +287,7 @@ public static function microsoftEdge() */ public static function iphone() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, )); @@ -298,7 +298,7 @@ public static function iphone() */ public static function ipad() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, )); @@ -309,7 +309,7 @@ public static function ipad() */ public static function opera() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); @@ -320,7 +320,7 @@ public static function opera() */ public static function safari() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); @@ -331,7 +331,7 @@ public static function safari() */ public static function phantomjs() { - return new self(array( + return new static(array( WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, )); diff --git a/lib/WebDriverBy.php b/lib/WebDriverBy.php index 92242ae56..af51c26b2 100644 --- a/lib/WebDriverBy.php +++ b/lib/WebDriverBy.php @@ -58,7 +58,7 @@ public function getValue() */ public static function className($class_name) { - return new self('class name', $class_name); + return new static('class name', $class_name); } /** @@ -69,7 +69,7 @@ public static function className($class_name) */ public static function cssSelector($css_selector) { - return new self('css selector', $css_selector); + return new static('css selector', $css_selector); } /** @@ -80,7 +80,7 @@ public static function cssSelector($css_selector) */ public static function id($id) { - return new self('id', $id); + return new static('id', $id); } /** @@ -91,7 +91,7 @@ public static function id($id) */ public static function name($name) { - return new self('name', $name); + return new static('name', $name); } /** @@ -102,7 +102,7 @@ public static function name($name) */ public static function linkText($link_text) { - return new self('link text', $link_text); + return new static('link text', $link_text); } /** @@ -114,7 +114,7 @@ public static function linkText($link_text) */ public static function partialLinkText($partial_link_text) { - return new self('partial link text', $partial_link_text); + return new static('partial link text', $partial_link_text); } /** @@ -125,7 +125,7 @@ public static function partialLinkText($partial_link_text) */ public static function tagName($tag_name) { - return new self('tag name', $tag_name); + return new static('tag name', $tag_name); } /** @@ -136,6 +136,6 @@ public static function tagName($tag_name) */ public static function xpath($xpath) { - return new self('xpath', $xpath); + return new static('xpath', $xpath); } } diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 8c069bd41..775d23cf5 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -55,7 +55,7 @@ protected function __construct($apply) */ public static function titleIs($title) { - return new self( + return new static( function ($driver) use ($title) { return $title === $driver->getTitle(); } @@ -71,7 +71,7 @@ function ($driver) use ($title) { */ public static function titleContains($title) { - return new self( + return new static( function ($driver) use ($title) { return strpos($driver->getTitle(), $title) !== false; } @@ -88,7 +88,7 @@ function ($driver) use ($title) { */ public static function presenceOfElementLocated(WebDriverBy $by) { - return new self( + return new static( function ($driver) use ($by) { return $driver->findElement($by); } @@ -106,7 +106,7 @@ function ($driver) use ($by) { */ public static function visibilityOfElementLocated(WebDriverBy $by) { - return new self( + return new static( function ($driver) use ($by) { try { $element = $driver->findElement($by); @@ -130,7 +130,7 @@ function ($driver) use ($by) { */ public static function visibilityOf(WebDriverElement $element) { - return new self( + return new static( function ($driver) use ($element) { return $element->isDisplayed() ? $element : null; } @@ -147,7 +147,7 @@ function ($driver) use ($element) { */ public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) { - return new self( + return new static( function ($driver) use ($by) { $elements = $driver->findElements($by); @@ -166,7 +166,7 @@ function ($driver) use ($by) { */ public static function textToBePresentInElement(WebDriverBy $by, $text) { - return new self( + return new static( function ($driver) use ($by, $text) { try { $element_text = $driver->findElement($by)->getText(); @@ -189,7 +189,7 @@ function ($driver) use ($by, $text) { */ public static function textToBePresentInElementValue(WebDriverBy $by, $text) { - return new self( + return new static( function ($driver) use ($by, $text) { try { $element_text = $driver->findElement($by)->getAttribute('value'); @@ -213,7 +213,7 @@ function ($driver) use ($by, $text) { */ public static function frameToBeAvailableAndSwitchToIt($frame_locator) { - return new self( + return new static( function ($driver) use ($frame_locator) { try { return $driver->switchTo()->frame($frame_locator); @@ -234,7 +234,7 @@ function ($driver) use ($frame_locator) { */ public static function invisibilityOfElementLocated(WebDriverBy $by) { - return new self( + return new static( function ($driver) use ($by) { try { return !($driver->findElement($by)->isDisplayed()); @@ -258,7 +258,7 @@ function ($driver) use ($by) { */ public static function invisibilityOfElementWithText(WebDriverBy $by, $text) { - return new self( + return new static( function ($driver) use ($by, $text) { try { return !($driver->findElement($by)->getText() === $text); @@ -284,7 +284,7 @@ public static function elementToBeClickable(WebDriverBy $by) $visibility_of_element_located = self::visibilityOfElementLocated($by); - return new self( + return new static( function ($driver) use ($visibility_of_element_located) { $element = call_user_func( $visibility_of_element_located->getApply(), @@ -312,7 +312,7 @@ function ($driver) use ($visibility_of_element_located) { */ public static function stalenessOf(WebDriverElement $element) { - return new self( + return new static( function ($driver) use ($element) { try { $element->isEnabled(); @@ -340,7 +340,7 @@ function ($driver) use ($element) { */ public static function refreshed(WebDriverExpectedCondition $condition) { - return new self( + return new static( function ($driver) use ($condition) { try { return call_user_func($condition->getApply(), $driver); @@ -375,14 +375,14 @@ public static function elementToBeSelected($element_or_by) public static function elementSelectionStateToBe($element_or_by, $selected) { if ($element_or_by instanceof WebDriverElement) { - return new self( + return new static( function ($driver) use ($element_or_by, $selected) { return $element_or_by->isSelected() === $selected; } ); } else { if ($element_or_by instanceof WebDriverBy) { - return new self( + return new static( function ($driver) use ($element_or_by, $selected) { try { $element = $driver->findElement($element_or_by); @@ -405,7 +405,7 @@ function ($driver) use ($element_or_by, $selected) { */ public static function alertIsPresent() { - return new self( + return new static( function ($driver) { try { // Unlike the Java code, we get a WebDriverAlert object regardless @@ -430,7 +430,7 @@ function ($driver) { */ public static function not(WebDriverExpectedCondition $condition) { - return new self( + return new static( function ($driver) use ($condition) { $result = call_user_func($condition->getApply(), $driver); From a67e8ec9674a0951c268c3e1b542c6925de8c055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 11 Oct 2016 21:42:33 +0200 Subject: [PATCH 044/600] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b24bc9bcb..0b067bed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - Added initial basic support of Microsoft Edge browser +- Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible ## 1.1.3 - 2016-08-10 - Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file From 395cf63e6d85715951143240e35479e5fb8b800c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 20 Sep 2016 18:41:55 +0200 Subject: [PATCH 045/600] Require PHP 5.5+ (fixes #324) --- .travis.yml | 5 +---- CHANGELOG.md | 1 + composer.json | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index eb8e94685..facb0d4db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,10 @@ language: php -sudo: false - php: - - 5.3 - - 5.4 - 5.5 - 5.6 - 7 + - 7.1 - hhvm matrix: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b067bed7..a74435bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - Added initial basic support of Microsoft Edge browser - Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible +- PHP version at least 5.5 is required ## 1.1.3 - 2016-08-10 - Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file diff --git a/composer.json b/composer.json index 227542bf1..e8afaf77e 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "source": "https://github.com/facebook/php-webdriver" }, "require": { - "php": ">=5.3.19", + "php": "^5.5 || ~7.0", "ext-curl": "*" }, "require-dev": { From 89d3c316cb9e71b4d20c94a37f1e65c8e5ed615a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 20 Sep 2016 18:52:08 +0200 Subject: [PATCH 046/600] Use PHP 5.5 features - class, short array syntax --- .php_cs | 32 ++- example.php | 18 +- lib/Chrome/ChromeDriver.php | 4 +- lib/Chrome/ChromeDriverService.php | 2 +- lib/Chrome/ChromeOptions.php | 6 +- lib/Firefox/FirefoxProfile.php | 8 +- lib/Interactions/WebDriverCompositeAction.php | 2 +- lib/JavaScriptExecutor.php | 4 +- lib/Remote/DesiredCapabilities.php | 50 ++--- lib/Remote/ExecuteMethod.php | 2 +- lib/Remote/HttpCommandExecutor.php | 209 ++++++++---------- lib/Remote/RemoteExecuteMethod.php | 2 +- lib/Remote/RemoteKeyboard.php | 16 +- lib/Remote/RemoteMouse.php | 10 +- lib/Remote/RemoteTargetLocator.php | 8 +- lib/Remote/RemoteTouchScreen.php | 34 +-- lib/Remote/RemoteWebDriver.php | 40 ++-- lib/Remote/RemoteWebElement.php | 56 ++--- lib/Remote/Service/DriverService.php | 14 +- lib/Support/Events/EventFiringWebDriver.php | 6 +- lib/Support/Events/EventFiringWebElement.php | 2 +- lib/WebDriverAction.php | 2 - lib/WebDriverAlert.php | 2 +- lib/WebDriverDispatcher.php | 4 +- lib/WebDriverExpectedCondition.php | 4 +- lib/WebDriverKeys.php | 4 +- lib/WebDriverNavigation.php | 2 +- lib/WebDriverOptions.php | 6 +- lib/WebDriverSelect.php | 2 +- lib/WebDriverTimeouts.php | 8 +- lib/WebDriverWindow.php | 18 +- tests/functional/WebDriverTestCase.php | 4 +- .../WebDriverButtonReleaseActionTest.php | 6 +- .../Internal/WebDriverClickActionTest.php | 6 +- .../WebDriverClickAndHoldActionTest.php | 6 +- .../WebDriverContextClickActionTest.php | 6 +- .../WebDriverDoubleClickActionTest.php | 6 +- .../Internal/WebDriverKeyDownActionTest.php | 8 +- .../Internal/WebDriverKeyUpActionTest.php | 8 +- .../Internal/WebDriverMouseMoveActionTest.php | 6 +- .../WebDriverMouseToOffsetActionTest.php | 6 +- .../Internal/WebDriverSendKeysActionTest.php | 10 +- tests/unit/Remote/DesiredCapabilitiesTest.php | 38 ++-- tests/unit/Remote/WebDriverCommandTest.php | 4 +- 44 files changed, 340 insertions(+), 351 deletions(-) diff --git a/.php_cs b/.php_cs index 752fb9606..0466edfbe 100644 --- a/.php_cs +++ b/.php_cs @@ -1,17 +1,24 @@ in(array(__DIR__ . '/lib', __DIR__ . '/tests')); + ->in([__DIR__ . '/lib', __DIR__ . '/tests']); return Symfony\CS\Config\Config::create() - ->fixers(array( + ->fixers([ + 'array_element_white_space_after_comma', 'duplicate_semicolon', 'extra_empty_lines', + 'function_typehint_space', + 'lowercase_cast', + 'method_argument_default_value', 'multiline_array_trailing_comma', 'namespace_no_leading_whitespace', + 'native_function_casing', 'new_with_braces', 'no_blank_lines_after_class_opening', 'no_empty_lines_after_phpdocs', + 'no_empty_phpdoc', + 'no_empty_statement', 'object_operator', 'operators_spaces', 'trim_array_spaces', @@ -20,6 +27,7 @@ return Symfony\CS\Config\Config::create() 'phpdoc_no_empty_return', 'phpdoc_no_package', 'phpdoc_scalar', + 'phpdoc_single_line_var_spacing', 'phpdoc_trim', 'phpdoc_types', 'phpdoc_order', @@ -27,15 +35,31 @@ return Symfony\CS\Config\Config::create() 'ordered_use', 'remove_leading_slash_use', 'remove_lines_between_uses', - 'function_typehint_space', + 'return', 'self_accessor', 'single_array_no_trailing_comma', 'single_blank_line_before_namespace', 'single_quote', + 'spaces_after_semicolon', + 'spaces_before_semicolon', 'spaces_cast', + 'standardize_not_equal', + 'ternary_spaces', + 'trim_array_spaces', + 'unary_operators_spaces', + 'unused_use', 'whitespacy_lines', + + // additional contrib checks + 'concat_with_spaces', 'newline_after_open_tag', - )) + 'no_useless_else', + 'no_useless_return', + 'php_unit_construct', + 'php_unit_dedicate_assert', + 'phpdoc_order', + 'short_array_syntax', + ]) ->level(Symfony\CS\FixerInterface::PSR2_LEVEL) ->setUsingCache(true) ->finder($finder); diff --git a/example.php b/example.php index 690a3b1c3..03b16728e 100644 --- a/example.php +++ b/example.php @@ -18,16 +18,16 @@ // adding cookie $driver->manage()->deleteAllCookies(); -$driver->manage()->addCookie(array( - 'name' => 'cookie_name', - 'value' => 'cookie_value', -)); +$driver->manage()->addCookie([ + 'name' => 'cookie_name', + 'value' => 'cookie_value', +]); $cookies = $driver->manage()->getCookies(); print_r($cookies); // click the link 'About' $link = $driver->findElement( - WebDriverBy::id('menu_about') + WebDriverBy::id('menu_about') ); $link->click(); @@ -39,15 +39,15 @@ // Search 'php' in the search box $input = $driver->findElement( - WebDriverBy::id('q') + WebDriverBy::id('q') ); $input->sendKeys('php')->submit(); // wait at most 10 seconds until at least one result is shown $driver->wait(10)->until( - WebDriverExpectedCondition::presenceOfAllElementsLocatedBy( - WebDriverBy::className('gsc-result') - ) + WebDriverExpectedCondition::presenceOfAllElementsLocatedBy( + WebDriverBy::className('gsc-result') + ) ); // close the Firefox diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 75131c215..be807d7bc 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -45,9 +45,9 @@ public function startSession($desired_capabilities) $command = new WebDriverCommand( null, DriverCommand::NEW_SESSION, - array( + [ 'desiredCapabilities' => $desired_capabilities->toArray(), - ) + ] ); $response = $this->executor->execute($command); $this->setSessionID($response->getSessionID()); diff --git a/lib/Chrome/ChromeDriverService.php b/lib/Chrome/ChromeDriverService.php index 4fb3b59e5..90b3d24f7 100644 --- a/lib/Chrome/ChromeDriverService.php +++ b/lib/Chrome/ChromeDriverService.php @@ -26,7 +26,7 @@ public static function createDefaultService() { $exe = getenv(self::CHROME_DRIVER_EXE_PROPERTY); $port = 9515; // TODO: Get another port if the default port is used. - $args = array("--port=$port"); + $args = ["--port=$port"]; $service = new static($exe, $port, $args); return $service; diff --git a/lib/Chrome/ChromeOptions.php b/lib/Chrome/ChromeOptions.php index 3af14b9c3..901dc5388 100644 --- a/lib/Chrome/ChromeOptions.php +++ b/lib/Chrome/ChromeOptions.php @@ -31,7 +31,7 @@ class ChromeOptions /** * @var array */ - private $arguments = array(); + private $arguments = []; /** * @var string */ @@ -39,11 +39,11 @@ class ChromeOptions /** * @var array */ - private $extensions = array(); + private $extensions = []; /** * @var array */ - private $experimentalOptions = array(); + private $experimentalOptions = []; /** * Sets the path of the Chrome executable. The path should be either absolute diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 925ac157f..6dd4d41b3 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -26,15 +26,15 @@ class FirefoxProfile /** * @var array */ - private $preferences = array(); + private $preferences = []; /** * @var array */ - private $extensions = array(); + private $extensions = []; /** * @var array */ - private $extensions_datas = array(); + private $extensions_datas = []; /** * @var string */ @@ -220,7 +220,7 @@ private function installExtension($extension, $profile_dir) } } // Get the extension id from the install manifest. - $matches = array(); + $matches = []; preg_match('#<' . $prefix . 'id>([^<]+)#', $xml->asXML(), $matches); if (isset($matches[1])) { $ext_dir = $profile_dir . '/extensions/' . $matches[1]; diff --git a/lib/Interactions/WebDriverCompositeAction.php b/lib/Interactions/WebDriverCompositeAction.php index f17cc4588..742544f59 100644 --- a/lib/Interactions/WebDriverCompositeAction.php +++ b/lib/Interactions/WebDriverCompositeAction.php @@ -22,7 +22,7 @@ */ class WebDriverCompositeAction implements WebDriverAction { - private $actions = array(); + private $actions = []; /** * Add an WebDriverAction to the sequence. diff --git a/lib/JavaScriptExecutor.php b/lib/JavaScriptExecutor.php index 61aa21b0e..d4a587acf 100644 --- a/lib/JavaScriptExecutor.php +++ b/lib/JavaScriptExecutor.php @@ -29,7 +29,7 @@ interface JavaScriptExecutor * @param array $arguments The arguments of the script. * @return mixed The return value of the script. */ - public function executeScript($script, array $arguments = array()); + public function executeScript($script, array $arguments = []); /** * Inject a snippet of JavaScript into the page for asynchronous execution in @@ -44,5 +44,5 @@ public function executeScript($script, array $arguments = array()); * @param array $arguments The arguments of the script. * @return mixed The value passed by the script to the callback. */ - public function executeAsyncScript($script, array $arguments = array()); + public function executeAsyncScript($script, array $arguments = []); } diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 2a132b576..a1cbfddf0 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -27,7 +27,7 @@ class DesiredCapabilities implements WebDriverCapabilities { private $capabilities; - public function __construct(array $capabilities = array()) + public function __construct(array $capabilities = []) { $this->capabilities = $capabilities; } @@ -201,10 +201,10 @@ private function get($key, $default = null) */ public static function android() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID, - )); + ]); } /** @@ -212,10 +212,10 @@ public static function android() */ public static function chrome() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); } /** @@ -223,10 +223,10 @@ public static function chrome() */ public static function firefox() { - $caps = new static(array( + $caps = new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); // disable the "Reader View" help tooltip, which can hide elements in the window.document $profile = new FirefoxProfile(); @@ -241,10 +241,10 @@ public static function firefox() */ public static function htmlUnit() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); } /** @@ -252,10 +252,10 @@ public static function htmlUnit() */ public static function htmlUnitWithJS() { - $caps = new static(array( + $caps = new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); return $caps->setJavascriptEnabled(true); } @@ -265,10 +265,10 @@ public static function htmlUnitWithJS() */ public static function internetExplorer() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, - )); + ]); } /** @@ -276,10 +276,10 @@ public static function internetExplorer() */ public static function microsoftEdge() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, - )); + ]); } /** @@ -287,10 +287,10 @@ public static function microsoftEdge() */ public static function iphone() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, - )); + ]); } /** @@ -298,10 +298,10 @@ public static function iphone() */ public static function ipad() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, - )); + ]); } /** @@ -309,10 +309,10 @@ public static function ipad() */ public static function opera() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); } /** @@ -320,10 +320,10 @@ public static function opera() */ public static function safari() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); } /** @@ -331,9 +331,9 @@ public static function safari() */ public static function phantomjs() { - return new static(array( + return new static([ WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS, WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, - )); + ]); } } diff --git a/lib/Remote/ExecuteMethod.php b/lib/Remote/ExecuteMethod.php index 38ad319e7..b12c25ed8 100644 --- a/lib/Remote/ExecuteMethod.php +++ b/lib/Remote/ExecuteMethod.php @@ -22,5 +22,5 @@ interface ExecuteMethod * @param array $parameters * @return WebDriverResponse */ - public function execute($command_name, array $parameters = array()); + public function execute($command_name, array $parameters = []); } diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 37670610d..9cfcd1fa4 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -29,142 +29,109 @@ class HttpCommandExecutor implements WebDriverCommandExecutor * @see * http://code.google.com/p/selenium/wiki/JsonWireProtocol#Command_Reference */ - protected static $commands = array( - DriverCommand::ACCEPT_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/accept_alert'), - DriverCommand::ADD_COOKIE => array('method' => 'POST', 'url' => '/session/:sessionId/cookie'), - DriverCommand::CLEAR_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'), - DriverCommand::CLICK_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'), - DriverCommand::CLOSE => array('method' => 'DELETE', 'url' => '/session/:sessionId/window'), - DriverCommand::DELETE_ALL_COOKIES => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie'), - DriverCommand::DELETE_COOKIE => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'), - DriverCommand::DISMISS_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'), - DriverCommand::ELEMENT_EQUALS => array( - 'method' => 'GET', - 'url' => '/session/:sessionId/element/:id/equals/:other', - ), - DriverCommand::FIND_CHILD_ELEMENT => array( - 'method' => 'POST', - 'url' => '/session/:sessionId/element/:id/element', - ), - DriverCommand::FIND_CHILD_ELEMENTS => array( - 'method' => 'POST', - 'url' => '/session/:sessionId/element/:id/elements', - ), - DriverCommand::EXECUTE_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute'), - DriverCommand::EXECUTE_ASYNC_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute_async'), - DriverCommand::FIND_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element'), - DriverCommand::FIND_ELEMENTS => array('method' => 'POST', 'url' => '/session/:sessionId/elements'), - DriverCommand::SWITCH_TO_FRAME => array('method' => 'POST', 'url' => '/session/:sessionId/frame'), - DriverCommand::SWITCH_TO_WINDOW => array('method' => 'POST', 'url' => '/session/:sessionId/window'), - DriverCommand::GET => array('method' => 'POST', 'url' => '/session/:sessionId/url'), - DriverCommand::GET_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/active'), - DriverCommand::GET_ALERT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/alert_text'), - DriverCommand::GET_ALL_COOKIES => array('method' => 'GET', 'url' => '/session/:sessionId/cookie'), - DriverCommand::GET_ALL_SESSIONS => array('method' => 'GET', 'url' => '/sessions'), - DriverCommand::GET_AVAILABLE_LOG_TYPES => array('method' => 'GET', 'url' => '/session/:sessionId/log/types'), - DriverCommand::GET_CURRENT_URL => array('method' => 'GET', 'url' => '/session/:sessionId/url'), - DriverCommand::GET_CURRENT_WINDOW_HANDLE => array( - 'method' => 'GET', - 'url' => '/session/:sessionId/window_handle', - ), - DriverCommand::GET_ELEMENT_ATTRIBUTE => array( + protected static $commands = [ + DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/accept_alert'], + DriverCommand::ADD_COOKIE => ['method' => 'POST', 'url' => '/session/:sessionId/cookie'], + DriverCommand::CLEAR_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'], + DriverCommand::CLICK_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'], + DriverCommand::CLOSE => ['method' => 'DELETE', 'url' => '/session/:sessionId/window'], + DriverCommand::DELETE_ALL_COOKIES => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie'], + DriverCommand::DELETE_COOKIE => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'], + DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'], + DriverCommand::ELEMENT_EQUALS => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/equals/:other'], + DriverCommand::FIND_CHILD_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/element'], + DriverCommand::FIND_CHILD_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/elements'], + DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute'], + DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute_async'], + DriverCommand::FIND_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element'], + DriverCommand::FIND_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/elements'], + DriverCommand::SWITCH_TO_FRAME => ['method' => 'POST', 'url' => '/session/:sessionId/frame'], + DriverCommand::SWITCH_TO_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window'], + DriverCommand::GET => ['method' => 'POST', 'url' => '/session/:sessionId/url'], + DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/active'], + DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert_text'], + DriverCommand::GET_ALL_COOKIES => ['method' => 'GET', 'url' => '/session/:sessionId/cookie'], + DriverCommand::GET_ALL_SESSIONS => ['method' => 'GET', 'url' => '/sessions'], + DriverCommand::GET_AVAILABLE_LOG_TYPES => ['method' => 'GET', 'url' => '/session/:sessionId/log/types'], + DriverCommand::GET_CURRENT_URL => ['method' => 'GET', 'url' => '/session/:sessionId/url'], + DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window_handle'], + DriverCommand::GET_ELEMENT_ATTRIBUTE => [ 'method' => 'GET', 'url' => '/session/:sessionId/element/:id/attribute/:name', - ), - DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => array( + ], + DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => [ 'method' => 'GET', 'url' => '/session/:sessionId/element/:id/css/:propertyName', - ), - DriverCommand::GET_ELEMENT_LOCATION => array( + ], + DriverCommand::GET_ELEMENT_LOCATION => [ 'method' => 'GET', 'url' => '/session/:sessionId/element/:id/location', - ), - DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => array( + ], + DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => [ 'method' => 'GET', 'url' => '/session/:sessionId/element/:id/location_in_view', - ), - DriverCommand::GET_ELEMENT_SIZE => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'), - DriverCommand::GET_ELEMENT_TAG_NAME => array( - 'method' => 'GET', - 'url' => '/session/:sessionId/element/:id/name', - ), - DriverCommand::GET_ELEMENT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'), - DriverCommand::GET_LOG => array('method' => 'POST', 'url' => '/session/:sessionId/log'), - DriverCommand::GET_PAGE_SOURCE => array('method' => 'GET', 'url' => '/session/:sessionId/source'), - DriverCommand::GET_SCREEN_ORIENTATION => array('method' => 'GET', 'url' => '/session/:sessionId/orientation'), - DriverCommand::GET_CAPABILITIES => array('method' => 'GET', 'url' => '/session/:sessionId'), - DriverCommand::GET_TITLE => array('method' => 'GET', 'url' => '/session/:sessionId/title'), - DriverCommand::GET_WINDOW_HANDLES => array('method' => 'GET', 'url' => '/session/:sessionId/window_handles'), - DriverCommand::GET_WINDOW_POSITION => array( + ], + DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'], + DriverCommand::GET_ELEMENT_TAG_NAME => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/name'], + DriverCommand::GET_ELEMENT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'], + DriverCommand::GET_LOG => ['method' => 'POST', 'url' => '/session/:sessionId/log'], + DriverCommand::GET_PAGE_SOURCE => ['method' => 'GET', 'url' => '/session/:sessionId/source'], + DriverCommand::GET_SCREEN_ORIENTATION => ['method' => 'GET', 'url' => '/session/:sessionId/orientation'], + DriverCommand::GET_CAPABILITIES => ['method' => 'GET', 'url' => '/session/:sessionId'], + DriverCommand::GET_TITLE => ['method' => 'GET', 'url' => '/session/:sessionId/title'], + DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window_handles'], + DriverCommand::GET_WINDOW_POSITION => [ 'method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/position', - ), - DriverCommand::GET_WINDOW_SIZE => array( - 'method' => 'GET', - 'url' => '/session/:sessionId/window/:windowHandle/size', - ), - DriverCommand::GO_BACK => array('method' => 'POST', 'url' => '/session/:sessionId/back'), - DriverCommand::GO_FORWARD => array('method' => 'POST', 'url' => '/session/:sessionId/forward'), - DriverCommand::IS_ELEMENT_DISPLAYED => array( + ], + DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/size'], + DriverCommand::GO_BACK => ['method' => 'POST', 'url' => '/session/:sessionId/back'], + DriverCommand::GO_FORWARD => ['method' => 'POST', 'url' => '/session/:sessionId/forward'], + DriverCommand::IS_ELEMENT_DISPLAYED => [ 'method' => 'GET', 'url' => '/session/:sessionId/element/:id/displayed', - ), - DriverCommand::IS_ELEMENT_ENABLED => array( - 'method' => 'GET', - 'url' => '/session/:sessionId/element/:id/enabled', - ), - DriverCommand::IS_ELEMENT_SELECTED => array( - 'method' => 'GET', - 'url' => '/session/:sessionId/element/:id/selected', - ), - DriverCommand::MAXIMIZE_WINDOW => array( + ], + DriverCommand::IS_ELEMENT_ENABLED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/enabled'], + DriverCommand::IS_ELEMENT_SELECTED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/selected'], + DriverCommand::MAXIMIZE_WINDOW => [ 'method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/maximize', - ), - DriverCommand::MOUSE_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/buttondown'), - DriverCommand::MOUSE_UP => array('method' => 'POST', 'url' => '/session/:sessionId/buttonup'), - DriverCommand::CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/click'), - DriverCommand::DOUBLE_CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/doubleclick'), - DriverCommand::MOVE_TO => array('method' => 'POST', 'url' => '/session/:sessionId/moveto'), - DriverCommand::NEW_SESSION => array('method' => 'POST', 'url' => '/session'), - DriverCommand::QUIT => array('method' => 'DELETE', 'url' => '/session/:sessionId'), - DriverCommand::REFRESH => array('method' => 'POST', 'url' => '/session/:sessionId/refresh'), - DriverCommand::UPLOAD_FILE => array('method' => 'POST', 'url' => '/session/:sessionId/file'), // undocumented - DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/keys'), - DriverCommand::SET_ALERT_VALUE => array('method' => 'POST', 'url' => '/session/:sessionId/alert_text'), - DriverCommand::SEND_KEYS_TO_ELEMENT => array( - 'method' => 'POST', - 'url' => '/session/:sessionId/element/:id/value', - ), - DriverCommand::IMPLICITLY_WAIT => array( - 'method' => 'POST', - 'url' => '/session/:sessionId/timeouts/implicit_wait', - ), - DriverCommand::SET_SCREEN_ORIENTATION => array('method' => 'POST', 'url' => '/session/:sessionId/orientation'), - DriverCommand::SET_TIMEOUT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts'), - DriverCommand::SET_SCRIPT_TIMEOUT => array( - 'method' => 'POST', - 'url' => '/session/:sessionId/timeouts/async_script', - ), - DriverCommand::SET_WINDOW_POSITION => array( + ], + DriverCommand::MOUSE_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/buttondown'], + DriverCommand::MOUSE_UP => ['method' => 'POST', 'url' => '/session/:sessionId/buttonup'], + DriverCommand::CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/click'], + DriverCommand::DOUBLE_CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/doubleclick'], + DriverCommand::MOVE_TO => ['method' => 'POST', 'url' => '/session/:sessionId/moveto'], + DriverCommand::NEW_SESSION => ['method' => 'POST', 'url' => '/session'], + DriverCommand::QUIT => ['method' => 'DELETE', 'url' => '/session/:sessionId'], + DriverCommand::REFRESH => ['method' => 'POST', 'url' => '/session/:sessionId/refresh'], + DriverCommand::UPLOAD_FILE => ['method' => 'POST', 'url' => '/session/:sessionId/file'], // undocumented + DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/keys'], + DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert_text'], + DriverCommand::SEND_KEYS_TO_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/value'], + DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/implicit_wait'], + DriverCommand::SET_SCREEN_ORIENTATION => ['method' => 'POST', 'url' => '/session/:sessionId/orientation'], + DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], + DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/async_script'], + DriverCommand::SET_WINDOW_POSITION => [ 'method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/position', - ), - DriverCommand::SET_WINDOW_SIZE => array( + ], + DriverCommand::SET_WINDOW_SIZE => [ 'method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/size', - ), - DriverCommand::SUBMIT_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'), - DriverCommand::SCREENSHOT => array('method' => 'GET', 'url' => '/session/:sessionId/screenshot'), - DriverCommand::TOUCH_SINGLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/click'), - DriverCommand::TOUCH_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/touch/down'), - DriverCommand::TOUCH_DOUBLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'), - DriverCommand::TOUCH_FLICK => array('method' => 'POST', 'url' => '/session/:sessionId/touch/flick'), - DriverCommand::TOUCH_LONG_PRESS => array('method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'), - DriverCommand::TOUCH_MOVE => array('method' => 'POST', 'url' => '/session/:sessionId/touch/move'), - DriverCommand::TOUCH_SCROLL => array('method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'), - DriverCommand::TOUCH_UP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/up'), - ); + ], + DriverCommand::SUBMIT_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'], + DriverCommand::SCREENSHOT => ['method' => 'GET', 'url' => '/session/:sessionId/screenshot'], + DriverCommand::TOUCH_SINGLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/click'], + DriverCommand::TOUCH_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/touch/down'], + DriverCommand::TOUCH_DOUBLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'], + DriverCommand::TOUCH_FLICK => ['method' => 'POST', 'url' => '/session/:sessionId/touch/flick'], + DriverCommand::TOUCH_LONG_PRESS => ['method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'], + DriverCommand::TOUCH_MOVE => ['method' => 'POST', 'url' => '/session/:sessionId/touch/move'], + DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'], + DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'], + ]; /** * @var string */ @@ -205,10 +172,10 @@ public function __construct($url, $http_proxy = null, $http_proxy_port = null) curl_setopt( $this->curl, CURLOPT_HTTPHEADER, - array( + [ 'Content-Type: application/json;charset=UTF-8', 'Accept: application/json', - ) + ] ); $this->setRequestTimeout(30000); $this->setConnectionTimeout(30000); @@ -317,7 +284,7 @@ public function execute(WebDriverCommand $command) if ($params && is_array($params)) { $msg .= sprintf(' with params: %s', json_encode($params)); } - WebDriverException::throwException(-1, $msg . "\n\n" . $error, array()); + WebDriverException::throwException(-1, $msg . "\n\n" . $error, []); } $results = json_decode($raw_results, true); diff --git a/lib/Remote/RemoteExecuteMethod.php b/lib/Remote/RemoteExecuteMethod.php index 5a995215e..ce66e5610 100644 --- a/lib/Remote/RemoteExecuteMethod.php +++ b/lib/Remote/RemoteExecuteMethod.php @@ -32,7 +32,7 @@ public function __construct(RemoteWebDriver $driver) * @param array $parameters * @return mixed */ - public function execute($command_name, array $parameters = array()) + public function execute($command_name, array $parameters = []) { return $this->driver->execute($command_name, $parameters); } diff --git a/lib/Remote/RemoteKeyboard.php b/lib/Remote/RemoteKeyboard.php index 7b2e114a2..b10b1ca72 100644 --- a/lib/Remote/RemoteKeyboard.php +++ b/lib/Remote/RemoteKeyboard.php @@ -43,9 +43,9 @@ public function __construct(RemoteExecuteMethod $executor) */ public function sendKeys($keys) { - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [ 'value' => WebDriverKeys::encode($keys), - )); + ]); return $this; } @@ -59,9 +59,9 @@ public function sendKeys($keys) */ public function pressKey($key) { - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( - 'value' => array((string) $key), - )); + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [ + 'value' => [(string) $key], + ]); return $this; } @@ -75,9 +75,9 @@ public function pressKey($key) */ public function releaseKey($key) { - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array( - 'value' => array((string) $key), - )); + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [ + 'value' => [(string) $key], + ]); return $this; } diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index 00a4ef7b6..48c578df7 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -44,9 +44,9 @@ public function __construct(RemoteExecuteMethod $executor) public function click(WebDriverCoordinates $where = null) { $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::CLICK, array( + $this->executor->execute(DriverCommand::CLICK, [ 'button' => 0, - )); + ]); return $this; } @@ -59,9 +59,9 @@ public function click(WebDriverCoordinates $where = null) public function contextClick(WebDriverCoordinates $where = null) { $this->moveIfNeeded($where); - $this->executor->execute(DriverCommand::CLICK, array( + $this->executor->execute(DriverCommand::CLICK, [ 'button' => 2, - )); + ]); return $this; } @@ -104,7 +104,7 @@ public function mouseMove( $x_offset = null, $y_offset = null ) { - $params = array(); + $params = []; if ($where !== null) { $params['element'] = $where->getAuxiliary(); } diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 67d2ad7cd..8eb38814f 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -42,7 +42,7 @@ public function __construct($executor, $driver) */ public function defaultContent() { - $params = array('id' => null); + $params = ['id' => null]; $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params); return $this->driver; @@ -58,12 +58,12 @@ public function defaultContent() public function frame($frame) { if ($frame instanceof WebDriverElement) { - $id = array('ELEMENT' => $frame->getID()); + $id = ['ELEMENT' => $frame->getID()]; } else { $id = (string) $frame; } - $params = array('id' => $id); + $params = ['id' => $id]; $this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params); return $this->driver; @@ -78,7 +78,7 @@ public function frame($frame) */ public function window($handle) { - $params = array('name' => (string) $handle); + $params = ['name' => (string) $handle]; $this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params); return $this->driver; diff --git a/lib/Remote/RemoteTouchScreen.php b/lib/Remote/RemoteTouchScreen.php index a052a6063..8c3981474 100644 --- a/lib/Remote/RemoteTouchScreen.php +++ b/lib/Remote/RemoteTouchScreen.php @@ -45,7 +45,7 @@ public function tap(WebDriverElement $element) { $this->executor->execute( DriverCommand::TOUCH_SINGLE_TAP, - array('element' => $element->getID()) + ['element' => $element->getID()] ); return $this; @@ -60,7 +60,7 @@ public function doubleTap(WebDriverElement $element) { $this->executor->execute( DriverCommand::TOUCH_DOUBLE_TAP, - array('element' => $element->getID()) + ['element' => $element->getID()] ); return $this; @@ -74,10 +74,10 @@ public function doubleTap(WebDriverElement $element) */ public function down($x, $y) { - $this->executor->execute(DriverCommand::TOUCH_DOWN, array( + $this->executor->execute(DriverCommand::TOUCH_DOWN, [ 'x' => $x, 'y' => $y, - )); + ]); return $this; } @@ -90,10 +90,10 @@ public function down($x, $y) */ public function flick($xspeed, $yspeed) { - $this->executor->execute(DriverCommand::TOUCH_FLICK, array( + $this->executor->execute(DriverCommand::TOUCH_FLICK, [ 'xspeed' => $xspeed, 'yspeed' => $yspeed, - )); + ]); return $this; } @@ -108,12 +108,12 @@ public function flick($xspeed, $yspeed) */ public function flickFromElement(WebDriverElement $element, $xoffset, $yoffset, $speed) { - $this->executor->execute(DriverCommand::TOUCH_FLICK, array( + $this->executor->execute(DriverCommand::TOUCH_FLICK, [ 'xoffset' => $xoffset, 'yoffset' => $yoffset, 'element' => $element->getID(), 'speed' => $speed, - )); + ]); return $this; } @@ -127,7 +127,7 @@ public function longPress(WebDriverElement $element) { $this->executor->execute( DriverCommand::TOUCH_LONG_PRESS, - array('element' => $element->getID()) + ['element' => $element->getID()] ); return $this; @@ -141,10 +141,10 @@ public function longPress(WebDriverElement $element) */ public function move($x, $y) { - $this->executor->execute(DriverCommand::TOUCH_MOVE, array( + $this->executor->execute(DriverCommand::TOUCH_MOVE, [ 'x' => $x, 'y' => $y, - )); + ]); return $this; } @@ -157,10 +157,10 @@ public function move($x, $y) */ public function scroll($xoffset, $yoffset) { - $this->executor->execute(DriverCommand::TOUCH_SCROLL, array( + $this->executor->execute(DriverCommand::TOUCH_SCROLL, [ 'xoffset' => $xoffset, 'yoffset' => $yoffset, - )); + ]); return $this; } @@ -174,11 +174,11 @@ public function scroll($xoffset, $yoffset) */ public function scrollFromElement(WebDriverElement $element, $xoffset, $yoffset) { - $this->executor->execute(DriverCommand::TOUCH_SCROLL, array( + $this->executor->execute(DriverCommand::TOUCH_SCROLL, [ 'element' => $element->getID(), 'xoffset' => $xoffset, 'yoffset' => $yoffset, - )); + ]); return $this; } @@ -191,10 +191,10 @@ public function scrollFromElement(WebDriverElement $element, $xoffset, $yoffset) */ public function up($x, $y) { - $this->executor->execute(DriverCommand::TOUCH_UP, array( + $this->executor->execute(DriverCommand::TOUCH_UP, [ 'x' => $x, 'y' => $y, - )); + ]); return $this; } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 4f885bc43..f1706e75b 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -94,7 +94,7 @@ public static function create( $command = new WebDriverCommand( null, DriverCommand::NEW_SESSION, - array('desiredCapabilities' => $desired_capabilities) + ['desiredCapabilities' => $desired_capabilities] ); $response = $executor->execute($command); @@ -133,7 +133,7 @@ public static function createBySessionID($session_id, $url = 'http://localhost:4 */ public function close() { - $this->execute(DriverCommand::CLOSE, array()); + $this->execute(DriverCommand::CLOSE, []); return $this; } @@ -148,7 +148,7 @@ public function close() */ public function findElement(WebDriverBy $by) { - $params = array('using' => $by->getMechanism(), 'value' => $by->getValue()); + $params = ['using' => $by->getMechanism(), 'value' => $by->getValue()]; $raw_element = $this->execute( DriverCommand::FIND_ELEMENT, $params @@ -168,13 +168,13 @@ public function findElement(WebDriverBy $by) */ public function findElements(WebDriverBy $by) { - $params = array('using' => $by->getMechanism(), 'value' => $by->getValue()); + $params = ['using' => $by->getMechanism(), 'value' => $by->getValue()]; $raw_elements = $this->execute( DriverCommand::FIND_ELEMENTS, $params ); - $elements = array(); + $elements = []; foreach ($raw_elements as $raw_element) { $elements[] = $this->newElement($raw_element['ELEMENT']); } @@ -191,7 +191,7 @@ public function findElements(WebDriverBy $by) */ public function get($url) { - $params = array('url' => (string) $url); + $params = ['url' => (string) $url]; $this->execute(DriverCommand::GET, $params); return $this; @@ -237,7 +237,7 @@ public function getWindowHandle() { return $this->execute( DriverCommand::GET_CURRENT_WINDOW_HANDLE, - array() + [] ); } @@ -248,7 +248,7 @@ public function getWindowHandle() */ public function getWindowHandles() { - return $this->execute(DriverCommand::GET_WINDOW_HANDLES, array()); + return $this->execute(DriverCommand::GET_WINDOW_HANDLES, []); } /** @@ -268,10 +268,10 @@ public function quit() */ private function prepareScriptArguments(array $arguments) { - $args = array(); + $args = []; foreach ($arguments as $key => $value) { if ($value instanceof WebDriverElement) { - $args[$key] = array('ELEMENT' => $value->getID()); + $args[$key] = ['ELEMENT' => $value->getID()]; } else { if (is_array($value)) { $value = $this->prepareScriptArguments($value); @@ -292,12 +292,12 @@ private function prepareScriptArguments(array $arguments) * @param array $arguments The arguments of the script. * @return mixed The return value of the script. */ - public function executeScript($script, array $arguments = array()) + public function executeScript($script, array $arguments = []) { - $params = array( + $params = [ 'script' => $script, 'args' => $this->prepareScriptArguments($arguments), - ); + ]; return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params); } @@ -315,12 +315,12 @@ public function executeScript($script, array $arguments = array()) * @param array $arguments The arguments of the script. * @return mixed The value passed by the script to the callback. */ - public function executeAsyncScript($script, array $arguments = array()) + public function executeAsyncScript($script, array $arguments = []) { - $params = array( + $params = [ 'script' => $script, 'args' => $this->prepareScriptArguments($arguments), - ); + ]; return $this->execute( DriverCommand::EXECUTE_ASYNC_SCRIPT, @@ -529,13 +529,13 @@ public static function getAllSessions($url = 'http://localhost:4444/wd/hub', $ti $command = new WebDriverCommand( null, DriverCommand::GET_ALL_SESSIONS, - array() + [] ); return $executor->execute($command)->getValue(); } - public function execute($command_name, $params = array()) + public function execute($command_name, $params = []) { $command = new WebDriverCommand( $this->sessionID, @@ -547,8 +547,8 @@ public function execute($command_name, $params = array()) $response = $this->executor->execute($command); return $response->getValue(); - } else { - return null; } + + return null; } } diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 217356592..d05b1e67a 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -64,7 +64,7 @@ public function clear() { $this->executor->execute( DriverCommand::CLEAR_ELEMENT, - array(':id' => $this->id) + [':id' => $this->id] ); return $this; @@ -79,7 +79,7 @@ public function click() { $this->executor->execute( DriverCommand::CLICK_ELEMENT, - array(':id' => $this->id) + [':id' => $this->id] ); return $this; @@ -96,11 +96,11 @@ public function click() */ public function findElement(WebDriverBy $by) { - $params = array( + $params = [ 'using' => $by->getMechanism(), 'value' => $by->getValue(), ':id' => $this->id, - ); + ]; $raw_element = $this->executor->execute( DriverCommand::FIND_CHILD_ELEMENT, $params @@ -119,17 +119,17 @@ public function findElement(WebDriverBy $by) */ public function findElements(WebDriverBy $by) { - $params = array( + $params = [ 'using' => $by->getMechanism(), 'value' => $by->getValue(), ':id' => $this->id, - ); + ]; $raw_elements = $this->executor->execute( DriverCommand::FIND_CHILD_ELEMENTS, $params ); - $elements = array(); + $elements = []; foreach ($raw_elements as $raw_element) { $elements[] = $this->newElement($raw_element['ELEMENT']); } @@ -145,10 +145,10 @@ public function findElements(WebDriverBy $by) */ public function getAttribute($attribute_name) { - $params = array( + $params = [ ':name' => $attribute_name, ':id' => $this->id, - ); + ]; return $this->executor->execute( DriverCommand::GET_ELEMENT_ATTRIBUTE, @@ -164,10 +164,10 @@ public function getAttribute($attribute_name) */ public function getCSSValue($css_property_name) { - $params = array( + $params = [ ':propertyName' => $css_property_name, ':id' => $this->id, - ); + ]; return $this->executor->execute( DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY, @@ -184,7 +184,7 @@ public function getLocation() { $location = $this->executor->execute( DriverCommand::GET_ELEMENT_LOCATION, - array(':id' => $this->id) + [':id' => $this->id] ); return new WebDriverPoint($location['x'], $location['y']); @@ -200,7 +200,7 @@ public function getLocationOnScreenOnceScrolledIntoView() { $location = $this->executor->execute( DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW, - array(':id' => $this->id) + [':id' => $this->id] ); return new WebDriverPoint($location['x'], $location['y']); @@ -239,7 +239,7 @@ public function getSize() { $size = $this->executor->execute( DriverCommand::GET_ELEMENT_SIZE, - array(':id' => $this->id) + [':id' => $this->id] ); return new WebDriverDimension($size['width'], $size['height']); @@ -258,7 +258,7 @@ public function getTagName() // Remove it when fixed to be consistent with the protocol. return strtolower($this->executor->execute( DriverCommand::GET_ELEMENT_TAG_NAME, - array(':id' => $this->id) + [':id' => $this->id] )); } @@ -272,7 +272,7 @@ public function getText() { return $this->executor->execute( DriverCommand::GET_ELEMENT_TEXT, - array(':id' => $this->id) + [':id' => $this->id] ); } @@ -286,7 +286,7 @@ public function isDisplayed() { return $this->executor->execute( DriverCommand::IS_ELEMENT_DISPLAYED, - array(':id' => $this->id) + [':id' => $this->id] ); } @@ -300,7 +300,7 @@ public function isEnabled() { return $this->executor->execute( DriverCommand::IS_ELEMENT_ENABLED, - array(':id' => $this->id) + [':id' => $this->id] ); } @@ -313,7 +313,7 @@ public function isSelected() { return $this->executor->execute( DriverCommand::IS_ELEMENT_SELECTED, - array(':id' => $this->id) + [':id' => $this->id] ); } @@ -327,17 +327,17 @@ public function sendKeys($value) { $local_file = $this->fileDetector->getLocalFile($value); if ($local_file === null) { - $params = array( + $params = [ 'value' => WebDriverKeys::encode($value), ':id' => $this->id, - ); + ]; $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); } else { $remote_path = $this->upload($local_file); - $params = array( + $params = [ 'value' => WebDriverKeys::encode($remote_path), ':id' => $this->id, - ); + ]; $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); } @@ -368,9 +368,9 @@ private function upload($local_file) $file_name = $info['basename']; $zip->addFile($local_file, $file_name); $zip->close(); - $params = array( + $params = [ 'file' => base64_encode(file_get_contents($temp_zip)), - ); + ]; $remote_path = $this->executor->execute( DriverCommand::UPLOAD_FILE, $params @@ -412,7 +412,7 @@ public function submit() { $this->executor->execute( DriverCommand::SUBMIT_ELEMENT, - array(':id' => $this->id) + [':id' => $this->id] ); return $this; @@ -436,10 +436,10 @@ public function getID() */ public function equals(WebDriverElement $other) { - return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, array( + return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, [ ':id' => $this->id, ':other' => $other->getID(), - )); + ]); } /** diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index 82a427a44..c32ce7246 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -51,7 +51,7 @@ class DriverService * @param array $args * @param array|null $environment Use the system environment if it is null */ - public function __construct($executable, $port, $args = array(), $environment = null) + public function __construct($executable, $port, $args = [], $environment = null) { $this->executable = self::checkExecutable($executable); $this->url = sprintf('http://localhost:%d', $port); @@ -76,14 +76,14 @@ public function start() return $this; } - $pipes = array(); + $pipes = []; $this->process = proc_open( sprintf('%s %s', $this->executable, implode(' ', $this->args)), - $descriptorspec = array( - 0 => array('pipe', 'r'), // stdin - 1 => array('pipe', 'w'), // stdout - 2 => array('pipe', 'a'), // stderr - ), + $descriptorspec = [ + 0 => ['pipe', 'r'], // stdin + 1 => ['pipe', 'w'], // stdout + 2 => ['pipe', 'a'], // stderr + ], $pipes, null, $this->environment diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index 7ea2242b0..2052d014f 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -120,7 +120,7 @@ public function findElements(WebDriverBy $by) { $this->dispatch('beforeFindBy', $by, null, $this); try { - $elements = array(); + $elements = []; foreach ($this->driver->findElements($by) as $element) { $elements[] = $this->newElement($element); } @@ -156,7 +156,7 @@ public function findElement(WebDriverBy $by) * @throws WebDriverException * @return mixed */ - public function executeScript($script, array $arguments = array()) + public function executeScript($script, array $arguments = []) { if (!$this->driver instanceof JavaScriptExecutor) { throw new UnsupportedOperationException( @@ -181,7 +181,7 @@ public function executeScript($script, array $arguments = array()) * @throws WebDriverException * @return mixed */ - public function executeAsyncScript($script, array $arguments = array()) + public function executeAsyncScript($script, array $arguments = []) { if (!$this->driver instanceof JavaScriptExecutor) { throw new UnsupportedOperationException( diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index 8f6f20d81..4a0384f53 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -162,7 +162,7 @@ public function findElements(WebDriverBy $by) $this->dispatcher->getDefaultDriver() ); try { - $elements = array(); + $elements = []; foreach ($this->element->findElements($by) as $element) { $elements[] = $this->newElement($element); } diff --git a/lib/WebDriverAction.php b/lib/WebDriverAction.php index e73b883ad..aead0a708 100644 --- a/lib/WebDriverAction.php +++ b/lib/WebDriverAction.php @@ -20,7 +20,5 @@ */ interface WebDriverAction { - /** - */ public function perform(); } diff --git a/lib/WebDriverAlert.php b/lib/WebDriverAlert.php index 4ba9f6168..2ef69172c 100644 --- a/lib/WebDriverAlert.php +++ b/lib/WebDriverAlert.php @@ -73,7 +73,7 @@ public function sendKeys($value) { $this->executor->execute( DriverCommand::SET_ALERT_VALUE, - array('text' => $value) + ['text' => $value] ); return $this; diff --git a/lib/WebDriverDispatcher.php b/lib/WebDriverDispatcher.php index 202a3ec93..782c84690 100644 --- a/lib/WebDriverDispatcher.php +++ b/lib/WebDriverDispatcher.php @@ -22,7 +22,7 @@ class WebDriverDispatcher /** * @var array */ - protected $listeners = array(); + protected $listeners = []; /** * @var EventFiringWebDriver */ @@ -83,7 +83,7 @@ public function unregister(WebDriverEventListener $listener) public function dispatch($method, $arguments) { foreach ($this->listeners as $listener) { - call_user_func_array(array($listener, $method), $arguments); + call_user_func_array([$listener, $method], $arguments); } return $this; diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 775d23cf5..54e2283b5 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -293,9 +293,9 @@ function ($driver) use ($visibility_of_element_located) { try { if ($element !== null && $element->isEnabled()) { return $element; - } else { - return null; } + + return null; } catch (StaleElementReferenceException $e) { return null; } diff --git a/lib/WebDriverKeys.php b/lib/WebDriverKeys.php index ecab819b6..57d37c1eb 100644 --- a/lib/WebDriverKeys.php +++ b/lib/WebDriverKeys.php @@ -98,10 +98,10 @@ public static function encode($keys) } if (is_string($keys)) { - $keys = array($keys); + $keys = [$keys]; } - $encoded = array(); + $encoded = []; foreach ($keys as $key) { if (is_array($key)) { // handle modified keys diff --git a/lib/WebDriverNavigation.php b/lib/WebDriverNavigation.php index 5e06d6257..6c7857d1d 100644 --- a/lib/WebDriverNavigation.php +++ b/lib/WebDriverNavigation.php @@ -80,7 +80,7 @@ public function refresh() */ public function to($url) { - $params = array('url' => (string) $url); + $params = ['url' => (string) $url]; $this->executor->execute(DriverCommand::GET, $params); return $this; diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index 8b80d3dba..d9c8bee44 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -55,7 +55,7 @@ public function addCookie(array $cookie) $this->validate($cookie); $this->executor->execute( DriverCommand::ADD_COOKIE, - array('cookie' => $cookie) + ['cookie' => $cookie] ); return $this; @@ -83,7 +83,7 @@ public function deleteCookieNamed($name) { $this->executor->execute( DriverCommand::DELETE_COOKIE, - array(':name' => $name) + [':name' => $name] ); return $this; @@ -174,7 +174,7 @@ public function getLog($log_type) { return $this->executor->execute( DriverCommand::GET_LOG, - array('type' => $log_type) + ['type' => $log_type] ); } diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index 158690b2f..4a9797a00 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -62,7 +62,7 @@ public function getOptions() */ public function getAllSelectedOptions() { - $selected_options = array(); + $selected_options = []; foreach ($this->getOptions() as $option) { if ($option->isSelected()) { $selected_options[] = $option; diff --git a/lib/WebDriverTimeouts.php b/lib/WebDriverTimeouts.php index 50b62f24f..3e5936a4b 100644 --- a/lib/WebDriverTimeouts.php +++ b/lib/WebDriverTimeouts.php @@ -40,7 +40,7 @@ public function implicitlyWait($seconds) { $this->executor->execute( DriverCommand::IMPLICITLY_WAIT, - array('ms' => $seconds * 1000) + ['ms' => $seconds * 1000] ); return $this; @@ -57,7 +57,7 @@ public function setScriptTimeout($seconds) { $this->executor->execute( DriverCommand::SET_SCRIPT_TIMEOUT, - array('ms' => $seconds * 1000) + ['ms' => $seconds * 1000] ); return $this; @@ -72,10 +72,10 @@ public function setScriptTimeout($seconds) */ public function pageLoadTimeout($seconds) { - $this->executor->execute(DriverCommand::SET_TIMEOUT, array( + $this->executor->execute(DriverCommand::SET_TIMEOUT, [ 'type' => 'page load', 'ms' => $seconds * 1000, - )); + ]); return $this; } diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index b63a681b3..828d4969c 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -40,7 +40,7 @@ public function getPosition() { $position = $this->executor->execute( DriverCommand::GET_WINDOW_POSITION, - array(':windowHandle' => 'current') + [':windowHandle' => 'current'] ); return new WebDriverPoint( @@ -59,7 +59,7 @@ public function getSize() { $size = $this->executor->execute( DriverCommand::GET_WINDOW_SIZE, - array(':windowHandle' => 'current') + [':windowHandle' => 'current'] ); return new WebDriverDimension( @@ -77,7 +77,7 @@ public function maximize() { $this->executor->execute( DriverCommand::MAXIMIZE_WINDOW, - array(':windowHandle' => 'current') + [':windowHandle' => 'current'] ); return $this; @@ -92,11 +92,11 @@ public function maximize() */ public function setSize(WebDriverDimension $size) { - $params = array( + $params = [ 'width' => $size->getWidth(), 'height' => $size->getHeight(), ':windowHandle' => 'current', - ); + ]; $this->executor->execute(DriverCommand::SET_WINDOW_SIZE, $params); return $this; @@ -111,11 +111,11 @@ public function setSize(WebDriverDimension $size) */ public function setPosition(WebDriverPoint $position) { - $params = array( + $params = [ 'x' => $position->getX(), 'y' => $position->getY(), ':windowHandle' => 'current', - ); + ]; $this->executor->execute(DriverCommand::SET_WINDOW_POSITION, $params); return $this; @@ -142,7 +142,7 @@ public function getScreenOrientation() public function setScreenOrientation($orientation) { $orientation = strtoupper($orientation); - if (!in_array($orientation, array('PORTRAIT', 'LANDSCAPE'))) { + if (!in_array($orientation, ['PORTRAIT', 'LANDSCAPE'])) { throw new IndexOutOfBoundsException( 'Orientation must be either PORTRAIT, or LANDSCAPE' ); @@ -150,7 +150,7 @@ public function setScreenOrientation($orientation) $this->executor->execute( DriverCommand::SET_SCREEN_ORIENTATION, - array('orientation' => $orientation) + ['orientation' => $orientation] ); return $this; diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index fca694854..6ebe98b61 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -31,11 +31,11 @@ protected function setUp() { $this->driver = RemoteWebDriver::create( 'http://localhost:4444/wd/hub', - array( + [ WebDriverCapabilityType::BROWSER_NAME //=> WebDriverBrowserType::FIREFOX, => WebDriverBrowserType::HTMLUNIT, - ) + ] ); } diff --git a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php index a192190f9..f2bb1b647 100644 --- a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php @@ -29,8 +29,8 @@ class WebDriverButtonReleaseActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverButtonReleaseAction = new WebDriverButtonReleaseAction( $this->webDriverMouse, $this->locationProvider @@ -39,7 +39,7 @@ public function setUp() public function testPerformSendsMouseUpCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('mouseUp')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php index 62162c77e..fdb868141 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php @@ -29,8 +29,8 @@ class WebDriverClickActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverClickAction = new WebDriverClickAction( $this->webDriverMouse, $this->locationProvider @@ -39,7 +39,7 @@ public function setUp() public function testPerformSendsClickCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('click')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php index 9dec8b9aa..eb3f4bc6f 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php @@ -29,8 +29,8 @@ class WebDriverClickAndHoldActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverClickAndHoldAction = new WebDriverClickAndHoldAction( $this->webDriverMouse, $this->locationProvider @@ -39,7 +39,7 @@ public function setUp() public function testPerformSendsMouseDownCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('mouseDown')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php index 2c5a92547..e9162f239 100644 --- a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php @@ -29,8 +29,8 @@ class WebDriverContextClickActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverContextClickAction = new WebDriverContextClickAction( $this->webDriverMouse, $this->locationProvider @@ -39,7 +39,7 @@ public function setUp() public function testPerformSendsContextClickCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('contextClick')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php index b83115f77..acd74550f 100644 --- a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php @@ -29,8 +29,8 @@ class WebDriverDoubleClickActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverDoubleClickAction = new WebDriverDoubleClickAction( $this->webDriverMouse, $this->locationProvider @@ -39,7 +39,7 @@ public function setUp() public function testPerformSendsDoubleClickCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('doubleClick')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php index e1cb8acbc..267b58b3e 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php @@ -32,9 +32,9 @@ class WebDriverKeyDownActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverKeyboard = $this->getMockBuilder(WebDriverKeyboard::class)->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverKeyDownAction = new WebDriverKeyDownAction( $this->webDriverKeyboard, @@ -45,7 +45,7 @@ public function setUp() public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('click')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php index c21ac24c1..970a35b0f 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php @@ -32,9 +32,9 @@ class WebDriverKeyUpActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverKeyboard = $this->getMockBuilder(WebDriverKeyboard::class)->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverKeyUpAction = new WebDriverKeyUpAction( $this->webDriverKeyboard, @@ -46,7 +46,7 @@ public function setUp() public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('click')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php index fe3ca9379..565530ad8 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php @@ -29,8 +29,8 @@ class WebDriverMouseMoveActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverMouseMoveAction = new WebDriverMouseMoveAction( $this->webDriverMouse, @@ -40,7 +40,7 @@ public function setUp() public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('mouseMove')->with($coords); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php index 37a2853ba..d2d5286a1 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php @@ -31,8 +31,8 @@ class WebDriverMouseToOffsetActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); $this->webDriverMoveToOffsetAction = new WebDriverMoveToOffsetAction( $this->webDriverMouse, @@ -44,7 +44,7 @@ public function setUp() public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverMouse->expects($this->once())->method('mouseMove')->with($coords, 150, 200); $this->locationProvider->expects($this->once())->method('getCoordinates')->will($this->returnValue($coords)); diff --git a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php index 82a736dea..9b06b3df7 100644 --- a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php @@ -34,11 +34,11 @@ class WebDriverSendKeysActionTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->webDriverKeyboard = $this->getMockBuilder('Facebook\WebDriver\WebDriverKeyboard')->getMock(); - $this->webDriverMouse = $this->getMockBuilder('Facebook\WebDriver\WebDriverMouse')->getMock(); - $this->locationProvider = $this->getMockBuilder('Facebook\WebDriver\Internal\WebDriverLocatable')->getMock(); + $this->webDriverKeyboard = $this->getMockBuilder(WebDriverKeyboard::class)->getMock(); + $this->webDriverMouse = $this->getMockBuilder(WebDriverMouse::class)->getMock(); + $this->locationProvider = $this->getMockBuilder(WebDriverLocatable::class)->getMock(); - $this->keys = array('t', 'e', 's', 't'); + $this->keys = ['t', 'e', 's', 't']; $this->webDriverSendKeysAction = new WebDriverSendKeysAction( $this->webDriverKeyboard, $this->webDriverMouse, @@ -49,7 +49,7 @@ public function setUp() public function testPerformFocusesOnElementAndSendPressKeyCommand() { - $coords = $this->getMockBuilder('Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates') + $coords = $this->getMockBuilder(WebDriverCoordinates::class) ->disableOriginalConstructor()->getMock(); $this->webDriverKeyboard->expects($this->once())->method('sendKeys')->with($this->keys); $this->webDriverMouse->expects($this->once())->method('click')->with($coords); diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index c68a747ed..dacdcd139 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -25,14 +25,14 @@ class DesiredCapabilitiesTest extends \PHPUnit_Framework_TestCase public function testShouldInstantiateWithCapabilitiesGivenInConstructor() { $capabilities = new DesiredCapabilities( - array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY) + ['fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY] ); $this->assertSame('fooVal', $capabilities->getCapability('fooKey')); $this->assertSame('ANY', $capabilities->getPlatform()); $this->assertSame( - array('fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY), + ['fooKey' => 'fooVal', WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY], $capabilities->toArray() ); } @@ -42,7 +42,7 @@ public function testShouldInstantiateEmptyInstance() $capabilities = new DesiredCapabilities(); $this->assertNull($capabilities->getCapability('foo')); - $this->assertSame(array(), $capabilities->toArray()); + $this->assertSame([], $capabilities->toArray()); } public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() @@ -93,7 +93,7 @@ public function testShouldProvideShortcutSetupForCapabilitiesOfEachBrowser( $expectedPlatform ) { /** @var DesiredCapabilities $capabilities */ - $capabilities = call_user_func(array('Facebook\WebDriver\Remote\DesiredCapabilities', $setupMethod)); + $capabilities = call_user_func([DesiredCapabilities::class, $setupMethod]); $this->assertSame($expectedBrowser, $capabilities->getBrowserName()); $this->assertSame($expectedPlatform, $capabilities->getPlatform()); @@ -104,20 +104,20 @@ public function testShouldProvideShortcutSetupForCapabilitiesOfEachBrowser( */ public function browserCapabilitiesProvider() { - return array( - array('android', WebDriverBrowserType::ANDROID, WebDriverPlatform::ANDROID), - array('chrome', WebDriverBrowserType::CHROME, WebDriverPlatform::ANY), - array('firefox', WebDriverBrowserType::FIREFOX, WebDriverPlatform::ANY), - array('htmlUnit', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), - array('htmlUnitWithJS', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY), - array('MicrosoftEdge', WebDriverBrowserType::MICROSOFT_EDGE, WebDriverPlatform::WINDOWS), - array('internetExplorer', WebDriverBrowserType::IE, WebDriverPlatform::WINDOWS), - array('iphone', WebDriverBrowserType::IPHONE, WebDriverPlatform::MAC), - array('ipad', WebDriverBrowserType::IPAD, WebDriverPlatform::MAC), - array('opera', WebDriverBrowserType::OPERA, WebDriverPlatform::ANY), - array('safari', WebDriverBrowserType::SAFARI, WebDriverPlatform::ANY), - array('phantomjs', WebDriverBrowserType::PHANTOMJS, WebDriverPlatform::ANY), - ); + return [ + ['android', WebDriverBrowserType::ANDROID, WebDriverPlatform::ANDROID], + ['chrome', WebDriverBrowserType::CHROME, WebDriverPlatform::ANY], + ['firefox', WebDriverBrowserType::FIREFOX, WebDriverPlatform::ANY], + ['htmlUnit', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY], + ['htmlUnitWithJS', WebDriverBrowserType::HTMLUNIT, WebDriverPlatform::ANY], + ['MicrosoftEdge', WebDriverBrowserType::MICROSOFT_EDGE, WebDriverPlatform::WINDOWS], + ['internetExplorer', WebDriverBrowserType::IE, WebDriverPlatform::WINDOWS], + ['iphone', WebDriverBrowserType::IPHONE, WebDriverPlatform::MAC], + ['ipad', WebDriverBrowserType::IPAD, WebDriverPlatform::MAC], + ['opera', WebDriverBrowserType::OPERA, WebDriverPlatform::ANY], + ['safari', WebDriverBrowserType::SAFARI, WebDriverPlatform::ANY], + ['phantomjs', WebDriverBrowserType::PHANTOMJS, WebDriverPlatform::ANY], + ]; } public function testShouldSetupFirefoxProfileAndDisableReaderViewForFirefoxBrowser() @@ -126,7 +126,7 @@ public function testShouldSetupFirefoxProfileAndDisableReaderViewForFirefoxBrows /** @var FirefoxProfile $firefoxProfile */ $firefoxProfile = $capabilities->getCapability(FirefoxDriver::PROFILE); - $this->assertInstanceOf('Facebook\WebDriver\Firefox\FirefoxProfile', $firefoxProfile); + $this->assertInstanceOf(FirefoxProfile::class, $firefoxProfile); $this->assertSame('false', $firefoxProfile->getPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED)); } diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php index 30a206119..9993c6ce5 100644 --- a/tests/unit/Remote/WebDriverCommandTest.php +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -19,10 +19,10 @@ class WebDriverCommandTest extends \PHPUnit_Framework_TestCase { public function testShouldSetOptionsUsingConstructor() { - $command = new WebDriverCommand('session-id-123', 'bar-baz-name', array('foo' => 'bar')); + $command = new WebDriverCommand('session-id-123', 'bar-baz-name', ['foo' => 'bar']); $this->assertSame('session-id-123', $command->getSessionID()); $this->assertSame('bar-baz-name', $command->getName()); - $this->assertSame(array('foo' => 'bar'), $command->getParameters()); + $this->assertSame(['foo' => 'bar'], $command->getParameters()); } } From 901814b5569e23f4084c2ac210b6170e995d6d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 12 Oct 2016 12:39:37 +0200 Subject: [PATCH 047/600] Extend addCookie docs --- lib/WebDriverOptions.php | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index d9c8bee44..2b298f20f 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -35,18 +35,17 @@ public function __construct(ExecuteMethod $executor) * Add a specific cookie. * * Here are the valid attributes of a cookie array. - * 'name' : string The name of the cookie; may not be null or an empty - * string. - * 'value' : string The cookie value; may not be null. - * 'path' : string The path the cookie is visible to. If left blank or set - * to null, will be set to "/". - * 'domain': string The domain the cookie is visible to. It should be null or - * the same as the domain of the current URL. - * 'secure': bool Whether this cookie requires a secure connection(https?). - * It should be null or equal to the security of the current - * URL. - * 'expiry': int The cookie's expiration date; may be null. + * 'name' : string The name of the cookie; may not be null or an empty string. + * 'value' : string The cookie value; may not be null. + * 'path' : string OPTIONAL The path the cookie is visible to. Defaults to "/" if omitted. + * 'domain' : string OPTIONAL The domain the cookie is visible to. Defaults to the current browsing context's + * document's URL domain if omitted. + * 'secure' : bool OPTIONAL Whether this cookie requires a secure connection (https). Defaults to false if + * omitted. + * 'httpOnly': bool OPTIONAL Whether the cookie is an HTTP only cookie. Defaults to false if omitted. + * 'expiry' : int OPTIONAL The cookie's expiration date, specified in seconds since Unix Epoch. * + * @see https://w3c.github.io/webdriver/webdriver-spec.html#cookies * @param array $cookie An array with key as the attributes mentioned above. * @return WebDriverOptions The current instance. */ @@ -93,8 +92,7 @@ public function deleteCookieNamed($name) * Get the cookie with a given name. * * @param string $name - * @return array The cookie, or null if no cookie with the given name is - * presented. + * @return array The cookie, or null if no cookie with the given name is presented. */ public function getCookieNamed($name) { From b1d4b9fb05fb0437d5f8f68bea1ecb26fa8cdbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 18 Sep 2016 23:19:01 +0200 Subject: [PATCH 048/600] Do not set URL placeholder params as part of POST body (fixes #323) --- composer.json | 3 +- lib/Remote/HttpCommandExecutor.php | 4 +- tests/unit/Remote/HttpCommandExecutorTest.php | 94 +++++++++++++++++++ 3 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 tests/unit/Remote/HttpCommandExecutorTest.php diff --git a/composer.json b/composer.json index e8afaf77e..a6b95a894 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ "require-dev": { "phpunit/phpunit": "4.6.* || ~5.0", "friendsofphp/php-cs-fixer": "^1.11", - "squizlabs/php_codesniffer": "^2.6" + "squizlabs/php_codesniffer": "^2.6", + "php-mock/php-mock-phpunit": "^1.1" }, "suggest": { "phpdocumentor/phpdocumentor": "2.*" diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 9cfcd1fa4..11b53536a 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -240,9 +240,7 @@ public function execute(WebDriverCommand $command) foreach ($params as $name => $value) { if ($name[0] === ':') { $url = str_replace($name, $value, $url); - if ($http_method != 'POST') { - unset($params[$name]); - } + unset($params[$name]); } } diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php new file mode 100644 index 000000000..268b3e873 --- /dev/null +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -0,0 +1,94 @@ +executor = new HttpCommandExecutor('http://localhost:4444/'); + } + + /** + * @dataProvider commandProvider + * @param int $command + * @param array $params + * @param string $expectedUrl + * @param string $expectedPostData + */ + public function testShouldSendRequestToAssembledUrl($command, array $params, $expectedUrl, $expectedPostData) + { + $command = new WebDriverCommand('foo-123', $command, $params); + + $curlSetoptMock = $this->getFunctionMock(__NAMESPACE__, 'curl_setopt'); + $curlSetoptMock->expects($this->at(0)) + ->with($this->anything(), CURLOPT_URL, $expectedUrl); + + $curlSetoptMock->expects($this->at(2)) + ->with($this->anything(), CURLOPT_POSTFIELDS, $expectedPostData); + + $curlExecMock = $this->getFunctionMock(__NAMESPACE__, 'curl_exec'); + $curlExecMock->expects($this->once()) + ->willReturn('{}'); + + $this->executor->execute($command); + } + + /** + * @return array[] + */ + public function commandProvider() + { + return [ + 'POST command having :id placeholder in url' => [ + DriverCommand::SEND_KEYS_TO_ELEMENT, + ['value' => 'submitted-value', ':id' => '1337'], + 'http://localhost:4444/session/foo-123/element/1337/value', + '{"value":"submitted-value"}', + ], + 'POST command without :id placeholder in url' => [ + DriverCommand::TOUCH_UP, + ['x' => 3, 'y' => 6], + 'http://localhost:4444/session/foo-123/touch/up', + '{"x":3,"y":6}', + ], + 'Extra useless placeholder parameter should be removed' => [ + DriverCommand::TOUCH_UP, + ['x' => 3, 'y' => 6, ':useless' => 'foo'], + 'http://localhost:4444/session/foo-123/touch/up', + '{"x":3,"y":6}', + ], + 'DELETE command' => [ + DriverCommand::DELETE_COOKIE, + [':name' => 'cookie-name'], + 'http://localhost:4444/session/foo-123/cookie/cookie-name', + null, + ], + 'GET command without session in URL' => [ + DriverCommand::GET_ALL_SESSIONS, + [], + 'http://localhost:4444/sessions', + null, + ], + ]; + } +} From 41ae93d12e3a4f5b0d7ddb00e538829b75133d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Oct 2016 15:57:00 +0200 Subject: [PATCH 049/600] Add and fix typehints --- lib/Chrome/ChromeDriver.php | 3 +- .../Internal/WebDriverCoordinates.php | 23 +++++- .../Internal/WebDriverKeysRelatedAction.php | 9 +++ .../Internal/WebDriverMouseAction.php | 4 + .../Internal/WebDriverMoveToOffsetAction.php | 12 +++ .../Internal/WebDriverSendKeysAction.php | 7 +- .../Internal/WebDriverSingleKeyAction.php | 5 +- .../Touch/WebDriverDownAction.php | 6 ++ .../Touch/WebDriverFlickAction.php | 6 ++ .../Touch/WebDriverFlickFromElementAction.php | 9 +++ lib/Interactions/WebDriverActions.php | 3 + lib/Interactions/WebDriverCompositeAction.php | 3 + lib/Remote/DesiredCapabilities.php | 3 + lib/Remote/RemoteExecuteMethod.php | 3 + lib/Remote/RemoteTargetLocator.php | 8 +- lib/Remote/RemoteWebDriver.php | 21 +++-- lib/Remote/RemoteWebElement.php | 9 +-- lib/Remote/UselessFileDetector.php | 3 - lib/Support/Events/EventFiringWebDriver.php | 8 +- lib/Support/Events/EventFiringWebElement.php | 2 + lib/WebDriverAlert.php | 6 +- lib/WebDriverBy.php | 6 ++ lib/WebDriverDimension.php | 13 +++- lib/WebDriverElement.php | 3 +- lib/WebDriverExpectedCondition.php | 76 ++++++++----------- lib/WebDriverOptions.php | 3 + lib/WebDriverTimeouts.php | 6 +- lib/WebDriverWait.php | 17 +++-- lib/WebDriverWindow.php | 6 +- 29 files changed, 197 insertions(+), 86 deletions(-) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index be807d7bc..b8aad6a07 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -40,7 +40,7 @@ public static function start(DesiredCapabilities $desired_capabilities = null, C return $driver; } - public function startSession($desired_capabilities) + public function startSession(DesiredCapabilities $desired_capabilities) { $command = new WebDriverCommand( null, @@ -76,6 +76,7 @@ public static function create( * @param string $url The url of the remote server * * @throws WebDriverException + * @return RemoteWebDriver|void */ public static function createBySessionID( $session_id, diff --git a/lib/Interactions/Internal/WebDriverCoordinates.php b/lib/Interactions/Internal/WebDriverCoordinates.php index ca7069cb5..911b7aece 100644 --- a/lib/Interactions/Internal/WebDriverCoordinates.php +++ b/lib/Interactions/Internal/WebDriverCoordinates.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Interactions\Internal; -use Closure; use Facebook\WebDriver\Exception\UnsupportedOperationException; use Facebook\WebDriver\WebDriverPoint; @@ -24,12 +23,30 @@ */ class WebDriverCoordinates { + /** + * @var null + */ private $onScreen; + /** + * @var callable + */ private $inViewPort; + /** + * @var callable + */ private $onPage; + /** + * @var string + */ private $auxiliary; - public function __construct($on_screen, Closure $in_view_port, Closure $on_page, $auxiliary) + /** + * @param null $on_screen + * @param callable $in_view_port + * @param callable $on_page + * @param string $auxiliary + */ + public function __construct($on_screen, callable $in_view_port, callable $on_page, $auxiliary) { $this->onScreen = $on_screen; $this->inViewPort = $in_view_port; @@ -65,7 +82,7 @@ public function onPage() } /** - * @return object The attached object. + * @return string The attached object id. */ public function getAuxiliary() { diff --git a/lib/Interactions/Internal/WebDriverKeysRelatedAction.php b/lib/Interactions/Internal/WebDriverKeysRelatedAction.php index b2f062750..899bb822e 100644 --- a/lib/Interactions/Internal/WebDriverKeysRelatedAction.php +++ b/lib/Interactions/Internal/WebDriverKeysRelatedAction.php @@ -24,8 +24,17 @@ */ abstract class WebDriverKeysRelatedAction { + /** + * @var WebDriverKeyboard + */ protected $keyboard; + /** + * @var WebDriverMouse + */ protected $mouse; + /** + * @var WebDriverLocatable|null + */ protected $locationProvider; /** diff --git a/lib/Interactions/Internal/WebDriverMouseAction.php b/lib/Interactions/Internal/WebDriverMouseAction.php index 8a13d86a7..2bec07386 100644 --- a/lib/Interactions/Internal/WebDriverMouseAction.php +++ b/lib/Interactions/Internal/WebDriverMouseAction.php @@ -32,6 +32,10 @@ class WebDriverMouseAction */ protected $locationProvider; + /** + * @param WebDriverMouse $mouse + * @param WebDriverLocatable|null $location_provider + */ public function __construct(WebDriverMouse $mouse, WebDriverLocatable $location_provider = null) { $this->mouse = $mouse; diff --git a/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php b/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php index 7fffa0189..29be343d2 100644 --- a/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php +++ b/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php @@ -21,9 +21,21 @@ class WebDriverMoveToOffsetAction extends WebDriverMouseAction implements WebDriverAction { + /** + * @var int|null + */ private $xOffset; + /** + * @var int|null + */ private $yOffset; + /** + * @param WebDriverMouse $mouse + * @param WebDriverLocatable|null $location_provider + * @param int|null $x_offset + * @param int|null $y_offset + */ public function __construct( WebDriverMouse $mouse, WebDriverLocatable $location_provider = null, diff --git a/lib/Interactions/Internal/WebDriverSendKeysAction.php b/lib/Interactions/Internal/WebDriverSendKeysAction.php index 14836be38..ef3ea0b71 100644 --- a/lib/Interactions/Internal/WebDriverSendKeysAction.php +++ b/lib/Interactions/Internal/WebDriverSendKeysAction.php @@ -22,7 +22,10 @@ class WebDriverSendKeysAction extends WebDriverKeysRelatedAction implements WebDriverAction { - private $keys; + /** + * @var string + */ + private $keys = ''; /** * @param WebDriverKeyboard $keyboard @@ -34,7 +37,7 @@ public function __construct( WebDriverKeyboard $keyboard, WebDriverMouse $mouse, WebDriverLocatable $location_provider = null, - $keys = null + $keys = '' ) { parent::__construct($keyboard, $mouse, $location_provider); $this->keys = $keys; diff --git a/lib/Interactions/Internal/WebDriverSingleKeyAction.php b/lib/Interactions/Internal/WebDriverSingleKeyAction.php index 174304d15..6311ee805 100644 --- a/lib/Interactions/Internal/WebDriverSingleKeyAction.php +++ b/lib/Interactions/Internal/WebDriverSingleKeyAction.php @@ -22,13 +22,14 @@ abstract class WebDriverSingleKeyAction extends WebDriverKeysRelatedAction implements WebDriverAction { - protected $key; + /** @var string */ + protected $key = ''; public function __construct( WebDriverKeyboard $keyboard, WebDriverMouse $mouse, WebDriverLocatable $location_provider = null, - $key = null + $key = '' ) { parent::__construct($keyboard, $mouse, $location_provider); $this->key = $key; diff --git a/lib/Interactions/Touch/WebDriverDownAction.php b/lib/Interactions/Touch/WebDriverDownAction.php index 46224aea2..5f392313c 100644 --- a/lib/Interactions/Touch/WebDriverDownAction.php +++ b/lib/Interactions/Touch/WebDriverDownAction.php @@ -19,7 +19,13 @@ class WebDriverDownAction extends WebDriverTouchAction implements WebDriverAction { + /** + * @var int + */ private $x; + /** + * @var int + */ private $y; /** diff --git a/lib/Interactions/Touch/WebDriverFlickAction.php b/lib/Interactions/Touch/WebDriverFlickAction.php index 52f43fde6..a32164d83 100644 --- a/lib/Interactions/Touch/WebDriverFlickAction.php +++ b/lib/Interactions/Touch/WebDriverFlickAction.php @@ -19,7 +19,13 @@ class WebDriverFlickAction extends WebDriverTouchAction implements WebDriverAction { + /** + * @var int + */ private $x; + /** + * @var int + */ private $y; /** diff --git a/lib/Interactions/Touch/WebDriverFlickFromElementAction.php b/lib/Interactions/Touch/WebDriverFlickFromElementAction.php index d91e84898..78445c256 100644 --- a/lib/Interactions/Touch/WebDriverFlickFromElementAction.php +++ b/lib/Interactions/Touch/WebDriverFlickFromElementAction.php @@ -20,8 +20,17 @@ class WebDriverFlickFromElementAction extends WebDriverTouchAction implements WebDriverAction { + /** + * @var int + */ private $x; + /** + * @var int + */ private $y; + /** + * @var int + */ private $speed; /** diff --git a/lib/Interactions/WebDriverActions.php b/lib/Interactions/WebDriverActions.php index 860cf8d5a..281b84dac 100644 --- a/lib/Interactions/WebDriverActions.php +++ b/lib/Interactions/WebDriverActions.php @@ -38,6 +38,9 @@ class WebDriverActions protected $mouse; protected $action; + /** + * @param WebDriver $driver + */ public function __construct(WebDriver $driver) { $this->driver = $driver; diff --git a/lib/Interactions/WebDriverCompositeAction.php b/lib/Interactions/WebDriverCompositeAction.php index 742544f59..75b879082 100644 --- a/lib/Interactions/WebDriverCompositeAction.php +++ b/lib/Interactions/WebDriverCompositeAction.php @@ -22,6 +22,9 @@ */ class WebDriverCompositeAction implements WebDriverAction { + /** + * @var array + */ private $actions = []; /** diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index a1cbfddf0..badd04313 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -25,6 +25,9 @@ class DesiredCapabilities implements WebDriverCapabilities { + /** + * @var array + */ private $capabilities; public function __construct(array $capabilities = []) diff --git a/lib/Remote/RemoteExecuteMethod.php b/lib/Remote/RemoteExecuteMethod.php index ce66e5610..4ab9e3890 100644 --- a/lib/Remote/RemoteExecuteMethod.php +++ b/lib/Remote/RemoteExecuteMethod.php @@ -17,6 +17,9 @@ class RemoteExecuteMethod implements ExecuteMethod { + /** + * @var RemoteWebDriver + */ private $driver; /** diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 8eb38814f..9b4fe2526 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -25,7 +25,13 @@ */ class RemoteTargetLocator implements WebDriverTargetLocator { + /** + * @var ExecuteMethod + */ protected $executor; + /** + * @var WebDriver + */ protected $driver; public function __construct($executor, $driver) @@ -103,7 +109,7 @@ public function alert() */ public function activeElement() { - $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT); + $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []); $method = new RemoteExecuteMethod($this->driver); return new RemoteWebElement($method, $response['ELEMENT']); diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index f1706e75b..a904024f5 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -142,8 +142,7 @@ public function close() * Find the first WebDriverElement using the given mechanism. * * @param WebDriverBy $by - * @return RemoteWebElement NoSuchElementException is thrown in - * HttpCommandExecutor if no element is found. + * @return RemoteWebElement NoSuchElementException is thrown in HttpCommandExecutor if no element is found. * @see WebDriverBy */ public function findElement(WebDriverBy $by) @@ -158,12 +157,10 @@ public function findElement(WebDriverBy $by) } /** - * Find all WebDriverElements within the current page using the given - * mechanism. + * Find all WebDriverElements within the current page using the given mechanism. * * @param WebDriverBy $by - * @return RemoteWebElement[] A list of all WebDriverElements, or an empty - * array if nothing matches + * @return RemoteWebElement[] A list of all WebDriverElements, or an empty array if nothing matches * @see WebDriverBy */ public function findElements(WebDriverBy $by) @@ -228,8 +225,7 @@ public function getTitle() } /** - * Return an opaque handle to this window that uniquely identifies it within - * this driver instance. + * Return an opaque handle to this window that uniquely identifies it within this driver instance. * * @return string The current window handle. */ @@ -369,8 +365,7 @@ public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) } /** - * An abstraction for managing stuff you would do in a browser menu. For - * example, adding and deleting cookies. + * An abstraction for managing stuff you would do in a browser menu. For example, adding and deleting cookies. * * @return WebDriverOptions */ @@ -380,8 +375,7 @@ public function manage() } /** - * An abstraction allowing the driver to access the browser's history and to - * navigate to a given URL. + * An abstraction allowing the driver to access the browser's history and to navigate to a given URL. * * @return WebDriverNavigation * @see WebDriverNavigation @@ -438,6 +432,9 @@ public function getTouch() return $this->touch; } + /** + * @return RemoteExecuteMethod + */ protected function getExecuteMethod() { if (!$this->executeMethod) { diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index d05b1e67a..dfc66d124 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -55,8 +55,7 @@ public function __construct(RemoteExecuteMethod $executor, $id) } /** - * If this element is a TEXTAREA or text INPUT element, this will clear the - * value. + * If this element is a TEXTAREA or text INPUT element, this will clear the value. * * @return RemoteWebElement The current instance. */ @@ -86,8 +85,7 @@ public function click() } /** - * Find the first WebDriverElement within this element using the given - * mechanism. + * Find the first WebDriverElement within this element using the given mechanism. * * @param WebDriverBy $by * @return RemoteWebElement NoSuchElementException is thrown in @@ -403,8 +401,7 @@ public function setFileDetector(FileDetector $detector) } /** - * If this current element is a form, or an element within a form, then this - * will be submitted to the remote server. + * If this current element is a form, or an element within a form, then this will be submitted to the remote server. * * @return RemoteWebElement The current instance. */ diff --git a/lib/Remote/UselessFileDetector.php b/lib/Remote/UselessFileDetector.php index f1e71f0c5..5ddd78e7d 100644 --- a/lib/Remote/UselessFileDetector.php +++ b/lib/Remote/UselessFileDetector.php @@ -17,9 +17,6 @@ class UselessFileDetector implements FileDetector { - /** - * @param string $file - */ public function getLocalFile($file) { return null; diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index 2052d014f..268b35ac7 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -119,14 +119,16 @@ public function get($url) public function findElements(WebDriverBy $by) { $this->dispatch('beforeFindBy', $by, null, $this); + $elements = []; + try { - $elements = []; foreach ($this->driver->findElements($by) as $element) { $elements[] = $this->newElement($element); } } catch (WebDriverException $exception) { $this->dispatchOnException($exception); } + $this->dispatch('afterFindBy', $by, null, $this); return $elements; @@ -140,11 +142,13 @@ public function findElements(WebDriverBy $by) public function findElement(WebDriverBy $by) { $this->dispatch('beforeFindBy', $by, null, $this); + try { $element = $this->newElement($this->driver->findElement($by)); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); } + $this->dispatch('afterFindBy', $by, null, $this); return $element; @@ -165,11 +169,13 @@ public function executeScript($script, array $arguments = []) } $this->dispatch('beforeScript', $script, $this); + try { $result = $this->driver->executeScript($script, $arguments); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); } + $this->dispatch('afterScript', $script, $this); return $result; diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index 4a0384f53..872c59c5e 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -133,11 +133,13 @@ public function findElement(WebDriverBy $by) $this, $this->dispatcher->getDefaultDriver() ); + try { $element = $this->newElement($this->element->findElement($by)); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); } + $this->dispatch( 'afterFindBy', $by, diff --git a/lib/WebDriverAlert.php b/lib/WebDriverAlert.php index 2ef69172c..b35132de6 100644 --- a/lib/WebDriverAlert.php +++ b/lib/WebDriverAlert.php @@ -16,15 +16,19 @@ namespace Facebook\WebDriver; use Facebook\WebDriver\Remote\DriverCommand; +use Facebook\WebDriver\Remote\ExecuteMethod; /** * An abstraction allowing the driver to manipulate the javascript alerts */ class WebDriverAlert { + /** + * @var ExecuteMethod + */ protected $executor; - public function __construct($executor) + public function __construct(ExecuteMethod $executor) { $this->executor = $executor; } diff --git a/lib/WebDriverBy.php b/lib/WebDriverBy.php index af51c26b2..f882683b3 100644 --- a/lib/WebDriverBy.php +++ b/lib/WebDriverBy.php @@ -24,7 +24,13 @@ */ class WebDriverBy { + /** + * @var string + */ private $mechanism; + /** + * @var string + */ private $value; protected function __construct($mechanism, $value) diff --git a/lib/WebDriverDimension.php b/lib/WebDriverDimension.php index 5b274e29a..111a77821 100644 --- a/lib/WebDriverDimension.php +++ b/lib/WebDriverDimension.php @@ -20,9 +20,19 @@ */ class WebDriverDimension { + /** + * @var int + */ private $height; + /** + * @var int + */ private $width; + /** + * @param int $width + * @param int $height + */ public function __construct($width, $height) { $this->width = $width; @@ -53,8 +63,7 @@ public function getWidth() * Check whether the given dimension is the same as the instance. * * @param WebDriverDimension $dimension The dimension to be compared with. - * @return bool Whether the height and the width are the same as the - * instance. + * @return bool Whether the height and the width are the same as the instance. */ public function equals(WebDriverDimension $dimension) { diff --git a/lib/WebDriverElement.php b/lib/WebDriverElement.php index 6eb7df5c6..2505368b3 100644 --- a/lib/WebDriverElement.php +++ b/lib/WebDriverElement.php @@ -21,8 +21,7 @@ interface WebDriverElement extends WebDriverSearchContext { /** - * If this element is a TEXTAREA or text INPUT element, this will clear the - * value. + * If this element is a TEXTAREA or text INPUT element, this will clear the value. * * @return WebDriverElement The current instance. */ diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 54e2283b5..b7cd53204 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -28,20 +28,21 @@ class WebDriverExpectedCondition { /** - * A closure function to be executed by WebDriverWait. It should return + * A callable function to be executed by WebDriverWait. It should return * a truthy value, mostly boolean or a WebDriverElement, on success. + * @var callable */ private $apply; /** - * @return (function():T) a closure function to be executed by WebDriverWait + * @return callable A callable function to be executed by WebDriverWait */ public function getApply() { return $this->apply; } - protected function __construct($apply) + protected function __construct(callable $apply) { $this->apply = $apply; } @@ -50,13 +51,12 @@ protected function __construct($apply) * An expectation for checking the title of a page. * * @param string $title The expected title, which must be an exact match. - * @return bool WebDriverExpectedCondition True when the title matches, - * false otherwise. + * @return bool WebDriverExpectedCondition True when the title matches, false otherwise. */ public static function titleIs($title) { return new static( - function ($driver) use ($title) { + function (WebDriver $driver) use ($title) { return $title === $driver->getTitle(); } ); @@ -66,13 +66,12 @@ function ($driver) use ($title) { * An expectation for checking substring of a page Title. * * @param string $title The expected substring of Title. - * @return bool WebDriverExpectedCondition True when in title, - * false otherwise. + * @return bool WebDriverExpectedCondition True when in title, false otherwise. */ public static function titleContains($title) { return new static( - function ($driver) use ($title) { + function (WebDriver $driver) use ($title) { return strpos($driver->getTitle(), $title) !== false; } ); @@ -83,13 +82,12 @@ function ($driver) use ($title) { * page. This does not necessarily mean that the element is visible. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition The element which - * is located. + * @return WebDriverExpectedCondition The element which is located. */ public static function presenceOfElementLocated(WebDriverBy $by) { return new static( - function ($driver) use ($by) { + function (WebDriver $driver) use ($by) { return $driver->findElement($by); } ); @@ -101,13 +99,12 @@ function ($driver) use ($by) { * also has a height and width that is greater than 0. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition The element which is - * located and visible. + * @return WebDriverExpectedCondition The element which is located and visible. */ public static function visibilityOfElementLocated(WebDriverBy $by) { return new static( - function ($driver) use ($by) { + function (WebDriver $driver) use ($by) { try { $element = $driver->findElement($by); @@ -125,13 +122,12 @@ function ($driver) use ($by) { * displayed but also has a height and width that is greater than 0. * * @param WebDriverElement $element The element to be checked. - * @return WebDriverExpectedCondition The same - * WebDriverElement once it is visible. + * @return WebDriverExpectedCondition The same WebDriverElement once it is visible. */ public static function visibilityOf(WebDriverElement $element) { return new static( - function ($driver) use ($element) { + function () use ($element) { return $element->isDisplayed() ? $element : null; } ); @@ -142,13 +138,12 @@ function ($driver) use ($element) { * web page. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition An array of WebDriverElements - * once they are located. + * @return WebDriverExpectedCondition An array of WebDriverElements once they are located. */ public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) { return new static( - function ($driver) use ($by) { + function (WebDriver $driver) use ($by) { $elements = $driver->findElements($by); return count($elements) > 0 ? $elements : null; @@ -167,7 +162,7 @@ function ($driver) use ($by) { public static function textToBePresentInElement(WebDriverBy $by, $text) { return new static( - function ($driver) use ($by, $text) { + function (WebDriver $driver) use ($by, $text) { try { $element_text = $driver->findElement($by)->getText(); @@ -190,7 +185,7 @@ function ($driver) use ($by, $text) { public static function textToBePresentInElementValue(WebDriverBy $by, $text) { return new static( - function ($driver) use ($by, $text) { + function (WebDriver $driver) use ($by, $text) { try { $element_text = $driver->findElement($by)->getAttribute('value'); @@ -214,7 +209,7 @@ function ($driver) use ($by, $text) { public static function frameToBeAvailableAndSwitchToIt($frame_locator) { return new static( - function ($driver) use ($frame_locator) { + function (WebDriver $driver) use ($frame_locator) { try { return $driver->switchTo()->frame($frame_locator); } catch (NoSuchFrameException $e) { @@ -229,13 +224,12 @@ function ($driver) use ($frame_locator) { * present on the DOM. * * @param WebDriverBy $by The locator used to find the element. - * @return bool WebDriverExpectedCondition Whether there is no element - * located. + * @return bool WebDriverExpectedCondition Whether there is no element located. */ public static function invisibilityOfElementLocated(WebDriverBy $by) { return new static( - function ($driver) use ($by) { + function (WebDriver $driver) use ($by) { try { return !($driver->findElement($by)->isDisplayed()); } catch (NoSuchElementException $e) { @@ -253,13 +247,12 @@ function ($driver) use ($by) { * * @param WebdriverBy $by The locator used to find the element. * @param string $text The text of the element. - * @return bool WebDriverExpectedCondition Whether the text is found in the - * element located. + * @return bool WebDriverExpectedCondition Whether the text is found in the element located. */ public static function invisibilityOfElementWithText(WebDriverBy $by, $text) { return new static( - function ($driver) use ($by, $text) { + function (WebDriver $driver) use ($by, $text) { try { return !($driver->findElement($by)->getText() === $text); } catch (NoSuchElementException $e) { @@ -285,7 +278,7 @@ public static function elementToBeClickable(WebDriverBy $by) self::visibilityOfElementLocated($by); return new static( - function ($driver) use ($visibility_of_element_located) { + function (WebDriver $driver) use ($visibility_of_element_located) { $element = call_user_func( $visibility_of_element_located->getApply(), $driver @@ -307,13 +300,12 @@ function ($driver) use ($visibility_of_element_located) { * Wait until an element is no longer attached to the DOM. * * @param WebDriverElement $element The element to wait for. - * @return bool WebDriverExpectedCondition false if the element is still - * attached to the DOM, true otherwise. + * @return bool WebDriverExpectedCondition false if the element is still attached to the DOM, true otherwise. */ public static function stalenessOf(WebDriverElement $element) { return new static( - function ($driver) use ($element) { + function () use ($element) { try { $element->isEnabled(); @@ -335,13 +327,12 @@ function ($driver) use ($element) { * when the second part of the condition is checked. * * @param WebDriverExpectedCondition $condition The condition wrapped. - * @return WebDriverExpectedCondition The return value of the - * getApply() of the given condition. + * @return WebDriverExpectedCondition The return value of the getApply() of the given condition. */ public static function refreshed(WebDriverExpectedCondition $condition) { return new static( - function ($driver) use ($condition) { + function (WebDriver $driver) use ($condition) { try { return call_user_func($condition->getApply(), $driver); } catch (StaleElementReferenceException $e) { @@ -376,14 +367,14 @@ public static function elementSelectionStateToBe($element_or_by, $selected) { if ($element_or_by instanceof WebDriverElement) { return new static( - function ($driver) use ($element_or_by, $selected) { + function () use ($element_or_by, $selected) { return $element_or_by->isSelected() === $selected; } ); } else { if ($element_or_by instanceof WebDriverBy) { return new static( - function ($driver) use ($element_or_by, $selected) { + function (WebDriver $driver) use ($element_or_by, $selected) { try { $element = $driver->findElement($element_or_by); @@ -400,13 +391,12 @@ function ($driver) use ($element_or_by, $selected) { /** * An expectation for whether an alert() box is present. * - * @return WebDriverExpectedCondition if alert() is present, - * null otherwise. + * @return WebDriverExpectedCondition if alert() is present, null otherwise. */ public static function alertIsPresent() { return new static( - function ($driver) { + function (WebDriver $driver) { try { // Unlike the Java code, we get a WebDriverAlert object regardless // of whether there is an alert. Calling getText() will throw @@ -431,7 +421,7 @@ function ($driver) { public static function not(WebDriverExpectedCondition $condition) { return new static( - function ($driver) use ($condition) { + function (WebDriver $driver) use ($condition) { $result = call_user_func($condition->getApply(), $driver); return !$result; diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index 2b298f20f..fef36f695 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -24,6 +24,9 @@ */ class WebDriverOptions { + /** + * @var ExecuteMethod + */ protected $executor; public function __construct(ExecuteMethod $executor) diff --git a/lib/WebDriverTimeouts.php b/lib/WebDriverTimeouts.php index 3e5936a4b..d62f2a124 100644 --- a/lib/WebDriverTimeouts.php +++ b/lib/WebDriverTimeouts.php @@ -16,15 +16,19 @@ namespace Facebook\WebDriver; use Facebook\WebDriver\Remote\DriverCommand; +use Facebook\WebDriver\Remote\ExecuteMethod; /** * Managing timeout behavior for WebDriver instances. */ class WebDriverTimeouts { + /** + * @var ExecuteMethod + */ protected $executor; - public function __construct($executor) + public function __construct(ExecuteMethod $executor) { $this->executor = $executor; } diff --git a/lib/WebDriverWait.php b/lib/WebDriverWait.php index a2297779d..37c44f94f 100644 --- a/lib/WebDriverWait.php +++ b/lib/WebDriverWait.php @@ -19,15 +19,23 @@ use Facebook\WebDriver\Exception\TimeOutException; /** - * A utility class, designed to help the user to wait until a condition turns - * true. + * A utility class, designed to help the user to wait until a condition turns true. * * @see WebDriverExpectedCondition. */ class WebDriverWait { + /** + * @var WebDriver + */ protected $driver; + /** + * @var int + */ protected $timeout; + /** + * @var int + */ protected $interval; public function __construct(WebDriver $driver, $timeout_in_second = null, $interval_in_millisecond = null) @@ -38,10 +46,9 @@ public function __construct(WebDriver $driver, $timeout_in_second = null, $inter } /** - * Calls the function provided with the driver as an argument until the return - * value is not falsey. + * Calls the function provided with the driver as an argument until the return value is not falsey. * - * @param (closure|WebDriverExpectedCondition) + * @param callable|WebDriverExpectedCondition $func_or_ec * @param string $message * * @throws NoSuchElementException diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index 828d4969c..68e49e015 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -17,15 +17,19 @@ use Facebook\WebDriver\Exception\IndexOutOfBoundsException; use Facebook\WebDriver\Remote\DriverCommand; +use Facebook\WebDriver\Remote\ExecuteMethod; /** * An abstraction allowing the driver to manipulate the browser's window */ class WebDriverWindow { + /** + * @var ExecuteMethod + */ protected $executor; - public function __construct($executor) + public function __construct(ExecuteMethod $executor) { $this->executor = $executor; } From e8a899389b012b6d2cb6681ee35c29952ec05264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Oct 2016 16:18:47 +0200 Subject: [PATCH 050/600] Use Symfony Process component to start local webdriver processes --- composer.json | 1 + lib/Remote/Service/DriverService.php | 32 +++++++++++++--------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index e8afaf77e..b0fcd0901 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ }, "require": { "php": "^5.5 || ~7.0", + "symfony/process": "^2.8 || ^3.1", "ext-curl": "*" }, "require-dev": { diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index c32ce7246..634c45864 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -17,7 +17,12 @@ use Exception; use Facebook\WebDriver\Net\URLChecker; +use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessBuilder; +/** + * Start local WebDriver service (when remote WebDriver server is not used). + */ class DriverService { /** @@ -41,7 +46,7 @@ class DriverService private $environment; /** - * @var resource + * @var Process */ private $process; @@ -76,18 +81,13 @@ public function start() return $this; } - $pipes = []; - $this->process = proc_open( - sprintf('%s %s', $this->executable, implode(' ', $this->args)), - $descriptorspec = [ - 0 => ['pipe', 'r'], // stdin - 1 => ['pipe', 'w'], // stdout - 2 => ['pipe', 'a'], // stderr - ], - $pipes, - null, - $this->environment - ); + $processBuilder = (new ProcessBuilder()) + ->setPrefix($this->executable) + ->setArguments($this->args) + ->addEnvironmentVariables($this->environment); + + $this->process = $processBuilder->getProcess(); + $this->process->start(); $checker = new URLChecker(); $checker->waitUntilAvailable(20 * 1000, $this->url . '/status'); @@ -104,7 +104,7 @@ public function stop() return $this; } - proc_terminate($this->process); + $this->process->stop(); $this->process = null; $checker = new URLChecker(); @@ -122,9 +122,7 @@ public function isRunning() return false; } - $status = proc_get_status($this->process); - - return $status['running']; + return $this->process->isRunning(); } /** From eafb4ca316b5aa5d7f085b45dcd7d7a4c34b4e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Oct 2016 17:15:38 +0200 Subject: [PATCH 051/600] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a74435bef..4791dbe55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased -- Added initial basic support of Microsoft Edge browser +- Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported) - Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible - PHP version at least 5.5 is required +- Fixed incompatibility with Appium, caused by redundant params present in requests to Selenium server ## 1.1.3 - 2016-08-10 - Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file From af21de3ae5306a8ca0bcc02a19735dadc43e83f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Oct 2016 17:16:51 +0200 Subject: [PATCH 052/600] Release 1.2.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4791dbe55..f89047b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.2.0 - 2016-10-14 - Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported) - Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible - PHP version at least 5.5 is required From d9d94a74444e81c6d0b195c3535edee24ce6428c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 18 Oct 2016 23:00:06 +0200 Subject: [PATCH 053/600] Add badges to readme --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6cdae5742..a09dd9843 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ -php-webdriver – WebDriver bindings for PHP -=========================================== +# php-webdriver – Selenium WebDriver bindings for PHP + +[![Latest Stable Version](https://img.shields.io/packagist/v/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) +[![Total Downloads](https://img.shields.io/packagist/dt/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) +[![License](https://img.shields.io/packagist/l/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) ## Description Php-webdriver library is PHP language binding for Selenium WebDriver, which allows you to control web browsers from PHP. From 6be7aea8ba2ccd249d3537ceb4ab3b58fa09a894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 18 Oct 2016 23:04:08 +0200 Subject: [PATCH 054/600] Add link to StackOverflow where one can also look for help --- README.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a09dd9843..8c3e2370a 100644 --- a/README.md +++ b/README.md @@ -81,17 +81,9 @@ Learn how to integrate it with PHPUnit [Blogpost](http://codeception.com/11-12-2 We have a great community willing to try and help you! -Currently we offer support in two manners: - -### Via our Facebook Group - -If you have questions or are an active contributor consider joining our facebook group and contributing to the communal discussion and support - -https://www.facebook.com/groups/phpwebdriver/ - -### Via Github - -If you're reading this you've already found our Github repository. If you have a question, feel free to submit it as an issue and our staff will do their best to help you as soon as possible. +- **Via our Facebook Group** - If you have questions or are an active contributor consider joining our [facebook group](https://www.facebook.com/groups/phpwebdriver/) and contributing to the communal discussion and support. +- **Via StackOverflow** - You can also [ask a question](https://stackoverflow.com/questions/ask?tags=php+selenium-webdriver) or find many already answered question on StackOverflow. +- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/facebook/php-webdriver/issues/new) as an new issue. ## Contributing From 87a7eae1af88425289bbf33e059d9c253148b59e Mon Sep 17 00:00:00 2001 From: "borgogelli@iubar.it" Date: Mon, 31 Oct 2016 21:42:41 +0100 Subject: [PATCH 055/600] Fix unused code in the URLChecker class --- lib/Net/URLChecker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Net/URLChecker.php b/lib/Net/URLChecker.php index 3a5d76316..97813202b 100644 --- a/lib/Net/URLChecker.php +++ b/lib/Net/URLChecker.php @@ -28,7 +28,7 @@ public function waitUntilAvailable($timeout_in_ms, $url) $end = microtime(true) + $timeout_in_ms / 1000; while ($end > microtime(true)) { - if ($this->getHTTPResponseCode($timeout_in_ms, $url) === 200) { + if ($this->getHTTPResponseCode($url) === 200) { return $this; } usleep(self::POLL_INTERVAL_MS); @@ -46,7 +46,7 @@ public function waitUntilUnavailable($timeout_in_ms, $url) $end = microtime(true) + $timeout_in_ms / 1000; while ($end > microtime(true)) { - if ($this->getHTTPResponseCode($timeout_in_ms, $url) !== 200) { + if ($this->getHTTPResponseCode($url) !== 200) { return $this; } usleep(self::POLL_INTERVAL_MS); @@ -59,7 +59,7 @@ public function waitUntilUnavailable($timeout_in_ms, $url) )); } - private function getHTTPResponseCode($timeout_in_ms, $url) + private function getHTTPResponseCode($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); From e9d0e39456d630e777596df33fb729456778989a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 2 Nov 2016 21:41:03 +0100 Subject: [PATCH 056/600] Clarify meaning of selenium server URL variable of RemoteWebDriver --- lib/Chrome/ChromeDriver.php | 6 +++--- lib/Remote/RemoteWebDriver.php | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index b8aad6a07..32ddf8f85 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -59,7 +59,7 @@ public function startSession(DesiredCapabilities $desired_capabilities) * @throws WebDriverException */ public static function create( - $url = 'http://localhost:4444/wd/hub', + $selenium_server_url = 'http://localhost:4444/wd/hub', $desired_capabilities = null, $connection_timeout_in_ms = null, $request_timeout_in_ms = null, @@ -73,14 +73,14 @@ public static function create( * Always throws an exception. Use ChromeDriver::start() instead. * * @param string $session_id The existing session id - * @param string $url The url of the remote server + * @param string $selenium_server_url The url of the remote Selenium WebDriver server * * @throws WebDriverException * @return RemoteWebDriver|void */ public static function createBySessionID( $session_id, - $url = 'http://localhost:4444/wd/hub' + $selenium_server_url = 'http://localhost:4444/wd/hub' ) { throw new WebDriverException('Please use ChromeDriver::start() instead.'); } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index a904024f5..964740ead 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -59,7 +59,7 @@ protected function __construct() /** * Construct the RemoteWebDriver by a desired capabilities. * - * @param string $url The url of the remote server + * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param DesiredCapabilities|array $desired_capabilities The desired capabilities * @param int|null $connection_timeout_in_ms * @param int|null $request_timeout_in_ms @@ -68,14 +68,14 @@ protected function __construct() * @return RemoteWebDriver */ public static function create( - $url = 'http://localhost:4444/wd/hub', + $selenium_server_url = 'http://localhost:4444/wd/hub', $desired_capabilities = null, $connection_timeout_in_ms = null, $request_timeout_in_ms = null, $http_proxy = null, $http_proxy_port = null ) { - $url = preg_replace('#/+$#', '', $url); + $selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url); // Passing DesiredCapabilities as $desired_capabilities is encouraged but // array is also accepted for legacy reason. @@ -83,7 +83,7 @@ public static function create( $desired_capabilities = $desired_capabilities->toArray(); } - $executor = new HttpCommandExecutor($url, $http_proxy, $http_proxy_port); + $executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port); if ($connection_timeout_in_ms !== null) { $executor->setConnectionTimeout($connection_timeout_in_ms); } @@ -113,15 +113,15 @@ public static function create( * browser for the whole test suite. You do not have to pass the desired * capabilities because the session was created before. * - * @param string $url The url of the remote server + * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param string $session_id The existing session id * @return RemoteWebDriver */ - public static function createBySessionID($session_id, $url = 'http://localhost:4444/wd/hub') + public static function createBySessionID($session_id, $selenium_server_url = 'http://localhost:4444/wd/hub') { $driver = new static(); $driver->setSessionID($session_id) - ->setCommandExecutor(new HttpCommandExecutor($url)); + ->setCommandExecutor(new HttpCommandExecutor($selenium_server_url)); return $driver; } @@ -514,13 +514,13 @@ public function getSessionID() /** * Get all selenium sessions. * - * @param string $url The url of the remote server + * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param int $timeout_in_ms * @return array */ - public static function getAllSessions($url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000) + public static function getAllSessions($selenium_server_url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000) { - $executor = new HttpCommandExecutor($url); + $executor = new HttpCommandExecutor($selenium_server_url); $executor->setConnectionTimeout($timeout_in_ms); $command = new WebDriverCommand( From e135093fdfc9b59860b003364b8c0fda76d2c7f8 Mon Sep 17 00:00:00 2001 From: Jan Travnicek Date: Thu, 1 Dec 2016 14:53:43 +0100 Subject: [PATCH 057/600] chore: fixed phpdoc in WebDriverWindow class --- lib/WebDriverWindow.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index 68e49e015..d48a70773 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -38,7 +38,7 @@ public function __construct(ExecuteMethod $executor) * Get the position of the current window, relative to the upper left corner * of the screen. * - * @return array The current window position. + * @return WebDriverPoint The current window position. */ public function getPosition() { @@ -57,7 +57,7 @@ public function getPosition() * Get the size of the current window. This will return the outer window * dimension, not just the view port. * - * @return array The current window size. + * @return WebDriverDimension The current window size. */ public function getSize() { From f45b91dc17096bcf0d3a2f566cd8f18be3a4a5e4 Mon Sep 17 00:00:00 2001 From: danielemontesi Date: Fri, 28 Oct 2016 17:58:42 +0200 Subject: [PATCH 058/600] Fix: const overwritten --- lib/Net/URLChecker.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Net/URLChecker.php b/lib/Net/URLChecker.php index 3a5d76316..dd197c46c 100644 --- a/lib/Net/URLChecker.php +++ b/lib/Net/URLChecker.php @@ -64,13 +64,13 @@ private function getHTTPResponseCode($timeout_in_ms, $url) $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + // The PHP doc indicates that CURLOPT_CONNECTTIMEOUT_MS constant is added in cURL 7.16.2 + // available since PHP 5.2.3. + if (!defined(CURLOPT_CONNECTTIMEOUT_MS)) { + define('CURLOPT_CONNECTTIMEOUT_MS', 156); // default value for CURLOPT_CONNECTTIMEOUT_MS + } curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS); - // There is a PHP bug in some versions which didn't define the constant. - curl_setopt( - $ch, - 156, // CURLOPT_CONNECTTIMEOUT_MS - self::CONNECT_TIMEOUT_MS - ); + $code = null; try { curl_exec($ch); From baaaec74d76e3ff0ff53f946e9a63364410cc0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 31 Dec 2016 18:25:21 +0100 Subject: [PATCH 059/600] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f89047b65..fadf18bf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve poratbility +- Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class ## 1.2.0 - 2016-10-14 - Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported) From 465f523eb5c5697d3863f623596366f898789426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 9 Dec 2016 11:56:19 +0100 Subject: [PATCH 060/600] Simplify build matrix --- .travis.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index facb0d4db..a2161a201 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,10 @@ matrix: # Add PHP 7 build to check codestyle only in PHP 7 build - php: 7 env: CHECK_CODESTYLE=1 + before_script: ~ + script: + - ./vendor/bin/php-cs-fixer fix --diff --dry-run + - ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/ env: global: @@ -28,15 +32,13 @@ install: - travis_retry composer install --no-interaction --prefer-source before_script: - - if [ -z "$CHECK_CODESTYLE" ]; then sh -e /etc/init.d/xvfb start; fi - - if [ -z "$CHECK_CODESTYLE" ]; then wget -q -t 3 http://selenium-release.storage.googleapis.com/2.45/selenium-server-standalone-2.45.0.jar; fi - - if [ -z "$CHECK_CODESTYLE" ]; then java -jar selenium-server-standalone-2.45.0.jar -log selenium.log; fi & - - if [ -z "$CHECK_CODESTYLE" ]; then until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done; fi + - sh -e /etc/init.d/xvfb start + - wget -q -t 3 http://selenium-release.storage.googleapis.com/2.45/selenium-server-standalone-2.45.0.jar + - java -jar selenium-server-standalone-2.45.0.jar -log selenium.log & + - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done script: - - if [ -n "$CHECK_CODESTYLE" ]; then ./vendor/bin/php-cs-fixer fix --diff --dry-run; fi - - if [ -n "$CHECK_CODESTYLE" ]; then ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/; fi - - if [ -z "$CHECK_CODESTYLE" ]; then ./vendor/bin/phpunit; fi + - ./vendor/bin/phpunit after_script: - cat selenium.log From c123f84528b66d7e566e0147c5f41f52759339a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 18 Dec 2016 02:18:42 +0100 Subject: [PATCH 061/600] Do not prefer source when installing from composer to take advantage from the Travis cache --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a2161a201..68a261845 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ before_install: - travis_retry composer self-update install: - - travis_retry composer install --no-interaction --prefer-source + - travis_retry composer install --no-interaction before_script: - sh -e /etc/init.d/xvfb start From 882d263a68179806e8fcd51806f2398f63d694e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 20:43:52 +0100 Subject: [PATCH 062/600] Make browser to run the functional tests against configurable --- tests/functional/WebDriverTestCase.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 6ebe98b61..080a30bca 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -15,9 +15,9 @@ namespace Facebook\WebDriver; +use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\WebDriverBrowserType; -use Facebook\WebDriver\Remote\WebDriverCapabilityType; /** * The base class for test cases. @@ -26,17 +26,23 @@ class WebDriverTestCase extends \PHPUnit_Framework_TestCase { /** @var RemoteWebDriver $driver */ protected $driver; + /** @var DesiredCapabilities */ + protected $desiredCapabilities; protected function setUp() { - $this->driver = RemoteWebDriver::create( - 'http://localhost:4444/wd/hub', - [ - WebDriverCapabilityType::BROWSER_NAME - //=> WebDriverBrowserType::FIREFOX, - => WebDriverBrowserType::HTMLUNIT, - ] - ); + $this->desiredCapabilities = new DesiredCapabilities(); + $serverUrl = 'http://localhost:4444/wd/hub'; + + if (getenv('BROWSER_NAME')) { + $browserName = getenv('BROWSER_NAME'); + } else { + $browserName = WebDriverBrowserType::HTMLUNIT; + } + + $this->desiredCapabilities->setBrowserName($browserName); + + $this->driver = RemoteWebDriver::create($serverUrl, $this->desiredCapabilities); } protected function tearDown() From d0f29eeee746ffe2b4f2c2da4686dccf77943ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 21:07:25 +0100 Subject: [PATCH 063/600] Use Selenium server 2.53.1 (with disabled marionette) for integration tests Selenium 3 will follow hopefully after 3.0.2 will be released. --- .travis.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 68a261845..609ba75cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,7 @@ env: cache: directories: - $HOME/.composer/cache + - jar before_install: - travis_retry composer self-update @@ -33,8 +34,13 @@ install: before_script: - sh -e /etc/init.d/xvfb start - - wget -q -t 3 http://selenium-release.storage.googleapis.com/2.45/selenium-server-standalone-2.45.0.jar - - java -jar selenium-server-standalone-2.45.0.jar -log selenium.log & + # TODO: upgrade to Selenium 3.0.2 (with latest HtmlUnit) once released, as HtmlUnit in 3.0.1 is broken + - if [ ! -f jar/selenium-server-standalone-2.53.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar; fi + - if [ ! -f jar/htmlunit-driver-standalone-2.20.jar ]; then wget -q -t 3 -P jar https://github.com/SeleniumHQ/htmlunit-driver/releases/download/2.20/htmlunit-driver-standalone-2.20.jar; fi + # Temporarily run HtmlUnit from standalone jar file (it was not part of Selenium server standalone in version 2.53) + - java -cp "jar/selenium-server-standalone-2.53.1.jar:jar/htmlunit-driver-standalone-2.20.jar" org.openqa.grid.selenium.GridLauncher -log selenium.log & + # TODO: use this after upgrade to Selenium 3.0.2 + #- /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.0.2.jar -log selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done script: @@ -42,3 +48,9 @@ script: after_script: - cat selenium.log + +addons: + apt: + packages: + - oracle-java8-installer + From e55a533a07397e2fbf65319bc8677eba213fc8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 20:44:36 +0100 Subject: [PATCH 064/600] Run tests on Travis also against Firefox --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 609ba75cf..21f11b4e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,9 @@ php: matrix: include: + # Add build to run tests against Firefox (other runs are agains HtmlUnit by default) + - php: 7 + env: BROWSER_NAME="firefox" # Add PHP 7 build to check codestyle only in PHP 7 build - php: 7 env: CHECK_CODESTYLE=1 @@ -50,7 +53,7 @@ after_script: - cat selenium.log addons: + firefox: "latest-esr" apt: packages: - oracle-java8-installer - From 75ee70317c914ec55b69df1966baf31a9396507c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 20:48:41 +0100 Subject: [PATCH 065/600] Ignore local phpunit.xml --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2444076bd..e2cc31fbb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ composer.phar composer.lock vendor .php_cs.cache +phpunit.xml # generic files to ignore *.lock From 49d39df13c960d1b1289c20a6bfc1ef978c4360e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 20:44:49 +0100 Subject: [PATCH 066/600] Minor phpdoc fixes --- lib/Remote/RemoteWebDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 964740ead..d06dc2e36 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -479,7 +479,7 @@ public function setCommandExecutor(WebDriverCommandExecutor $executor) } /** - * Set the command executor of this RemoteWebdriver + * Get the command executor of this RemoteWebdriver * * @return HttpCommandExecutor */ @@ -512,7 +512,7 @@ public function getSessionID() } /** - * Get all selenium sessions. + * Returns a list of the currently active sessions. * * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param int $timeout_in_ms From bdf7e2ecc718503b49836851933d656fc7955f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 20:22:05 +0100 Subject: [PATCH 067/600] Functional tests for RemoteWebDriver --- tests/functional/FileUploadTest.php | 4 +- .../{BaseTest.php => FindElementTest.php} | 29 +-- tests/functional/RemoteWebDriverTest.php | 202 ++++++++++++++++++ tests/functional/html/index.html | 20 +- tests/functional/html/open_new_window.html | 8 + tests/functional/html/upload.html | 8 +- 6 files changed, 239 insertions(+), 32 deletions(-) rename tests/functional/{BaseTest.php => FindElementTest.php} (84%) create mode 100644 tests/functional/RemoteWebDriverTest.php create mode 100644 tests/functional/html/open_new_window.html diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index 29b878d9f..57ebff23c 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -31,7 +31,7 @@ public function testFileUploading() $file_input = $this->driver->findElement(WebDriverBy::id('upload')); $file_input->setFileDetector(new LocalFileDetector()) ->sendKeys(__DIR__ . '/files/FileUploadTestCaseFile.txt'); - self::assertNotEquals($this->getFilePath(), $file_input->getAttribute('value')); + $this->assertNotEquals($this->getFilePath(), $file_input->getAttribute('value')); } public function testUselessFileDetectorSendKeys() @@ -39,7 +39,7 @@ public function testUselessFileDetectorSendKeys() $this->driver->get($this->getTestPath('upload.html')); $file_input = $this->driver->findElement(WebDriverBy::id('upload')); $file_input->sendKeys($this->getFilePath()); - self::assertEquals($this->getFilePath(), $file_input->getAttribute('value')); + $this->assertEquals($this->getFilePath(), $file_input->getAttribute('value')); } private function getFilePath() diff --git a/tests/functional/BaseTest.php b/tests/functional/FindElementTest.php similarity index 84% rename from tests/functional/BaseTest.php rename to tests/functional/FindElementTest.php index c9c522651..f479fc9bc 100644 --- a/tests/functional/BaseTest.php +++ b/tests/functional/FindElementTest.php @@ -15,21 +15,12 @@ namespace Facebook\WebDriver; -class BaseTest extends WebDriverTestCase +class FindElementTest extends WebDriverTestCase { - public function testGetTitle() - { - $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( - 'php-webdriver test page', - $this->driver->getTitle() - ); - } - public function testGetText() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Welcome to the facebook/php-webdriver testing page.', $this->driver->findElement(WebDriverBy::id('welcome'))->getText() ); @@ -38,7 +29,7 @@ public function testGetText() public function testGetById() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Test by ID', $this->driver->findElement(WebDriverBy::id('id_test'))->getText() ); @@ -47,7 +38,7 @@ public function testGetById() public function testGetByClassName() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Test by Class', $this->driver->findElement(WebDriverBy::className('test_class'))->getText() ); @@ -56,7 +47,7 @@ public function testGetByClassName() public function testGetByCssSelector() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Test by Class', $this->driver->findElement(WebDriverBy::cssSelector('.test_class'))->getText() ); @@ -65,7 +56,7 @@ public function testGetByCssSelector() public function testGetByLinkText() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Click here', $this->driver->findElement(WebDriverBy::linkText('Click here'))->getText() ); @@ -74,7 +65,7 @@ public function testGetByLinkText() public function testGetByName() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Test Value', $this->driver->findElement(WebDriverBy::name('test_name'))->getAttribute('value') ); @@ -83,7 +74,7 @@ public function testGetByName() public function testGetByXpath() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Test Value', $this->driver->findElement(WebDriverBy::xpath('//input[@name="test_name"]'))->getAttribute('value') ); @@ -92,7 +83,7 @@ public function testGetByXpath() public function testGetByPartialLinkText() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Click here', $this->driver->findElement(WebDriverBy::partialLinkText('Click'))->getText() ); @@ -101,7 +92,7 @@ public function testGetByPartialLinkText() public function testGetByTagName() { $this->driver->get($this->getTestPath('index.html')); - self::assertEquals( + $this->assertEquals( 'Test Value', $this->driver->findElement(WebDriverBy::tagName('input'))->getAttribute('value') ); diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php new file mode 100644 index 000000000..0f9691c96 --- /dev/null +++ b/tests/functional/RemoteWebDriverTest.php @@ -0,0 +1,202 @@ +driver->get($this->getTestPath('index.html')); + + $this->assertEquals( + 'php-webdriver test page', + $this->driver->getTitle() + ); + } + + public function testShouldGetCurrentUrl() + { + $this->driver->get($this->getTestPath('index.html')); + + $this->assertContains( + '/index.html', + $this->driver->getCurrentURL() + ); + } + + public function testShouldGetPageSource() + { + $this->driver->get($this->getTestPath('index.html')); + + $source = $this->driver->getPageSource(); + $this->assertContains('

', $source); + $this->assertContains('Welcome to the facebook/php-webdriver testing page.', $source); + } + + public function testShouldGetSessionId() + { + $sessionId = $this->driver->getSessionID(); + + $this->assertInternalType('string', $sessionId); + $this->assertNotEmpty($sessionId); + } + + public function testShouldGetAllSessions() + { + $sessions = RemoteWebDriver::getAllSessions(); + + $this->assertInternalType('array', $sessions); + $this->assertCount(1, $sessions); + + $this->assertArrayHasKey('capabilities', $sessions[0]); + $this->assertArrayHasKey('id', $sessions[0]); + $this->assertArrayHasKey('class', $sessions[0]); + } + + public function testShouldQuitAndUnsetExecutor() + { + $this->assertCount(1, RemoteWebDriver::getAllSessions()); + $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); + + $this->driver->quit(); + + $this->assertCount(0, RemoteWebDriver::getAllSessions()); + $this->assertNull($this->driver->getCommandExecutor()); + } + + public function testShouldGetWindowHandles() + { + $this->driver->get($this->getTestPath('open_new_window.html')); + + $windowHandle = $this->driver->getWindowHandle(); + $windowHandles = $this->driver->getWindowHandles(); + + $this->assertInternalType('string', $windowHandle); + $this->assertNotEmpty($windowHandle); + $this->assertSame([$windowHandle], $windowHandles); + + // Open second window + $this->driver->findElement(WebDriverBy::cssSelector('a'))->click(); + + $this->assertCount(2, $this->driver->getWindowHandles()); + } + + public function testShouldCloseWindow() + { + $this->driver->get($this->getTestPath('open_new_window.html')); + $this->driver->findElement(WebDriverBy::cssSelector('a'))->click(); + + $this->assertCount(2, $this->driver->getWindowHandles()); + + $this->driver->close(); + + $this->assertCount(1, $this->driver->getWindowHandles()); + } + + public function testShouldExecuteScriptAndDoNotBlockExecution() + { + $this->driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement(WebDriverBy::id('id_test')); + $this->assertSame('Test by ID', $element->getText()); + + $this->driver->executeScript(' + setTimeout( + function(){document.getElementById("id_test").innerHTML = "Text changed by script"}, + 250 + )'); + + // Make sure the script don't block the test execution + $this->assertSame('Test by ID', $element->getText()); + + // If we wait, the script should be executed + usleep(300000); // wait 300 ms + $this->assertSame('Text changed by script', $element->getText()); + } + + public function testShouldExecuteAsyncScriptAndWaitUntilItIsFinished() + { + $this->driver->manage()->timeouts()->setScriptTimeout(1); + + $this->driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement(WebDriverBy::id('id_test')); + $this->assertSame('Test by ID', $element->getText()); + + $this->driver->executeAsyncScript( + 'var callback = arguments[arguments.length - 1]; + setTimeout( + function(){ + document.getElementById("id_test").innerHTML = "Text changed by script"; + callback(); + }, + 250 + );' + ); + + // The result must be immediately available, as the executeAsyncScript should block the execution until the + // callback is called. + $this->assertSame('Text changed by script', $element->getText()); + } + + public function testShouldTakeScreenshot() + { + if (!extension_loaded('gd')) { + $this->markTestSkipped('GD extension must be enabled'); + } + if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Screenshots are not supported by HtmlUnit browser'); + } + + $this->driver->get($this->getTestPath('index.html')); + + $outputPng = $this->driver->takeScreenshot(); + + $image = imagecreatefromstring($outputPng); + $this->assertInternalType('resource', $image); + + $this->assertGreaterThan(0, imagesx($image)); + $this->assertGreaterThan(0, imagesy($image)); + } + + public function testShouldSaveScreenshotToFile() + { + if (!extension_loaded('gd')) { + $this->markTestSkipped('GD extension must be enabled'); + } + if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Screenshots are not supported by HtmlUnit browser'); + } + + $screenshotPath = sys_get_temp_dir() . '/selenium-screenshot.png'; + + $this->driver->get($this->getTestPath('index.html')); + + $this->driver->takeScreenshot($screenshotPath); + + $image = imagecreatefrompng($screenshotPath); + $this->assertInternalType('resource', $image); + + $this->assertGreaterThan(0, imagesx($image)); + $this->assertGreaterThan(0, imagesy($image)); + + unlink($screenshotPath); + } +} diff --git a/tests/functional/html/index.html b/tests/functional/html/index.html index 6bafefdc9..419b41ee2 100644 --- a/tests/functional/html/index.html +++ b/tests/functional/html/index.html @@ -1,12 +1,18 @@ - php-webdriver test page + php-webdriver test page -

Welcome to the facebook/php-webdriver testing page.

-

Test by ID

-

Test by Class

- Click here - +

Welcome to the facebook/php-webdriver testing page.

+

Test by ID

+

Test by Class

+ Click here + + +
    +
  • First
  • +
  • Second
  • +
  • Third
  • +
- \ No newline at end of file + diff --git a/tests/functional/html/open_new_window.html b/tests/functional/html/open_new_window.html new file mode 100644 index 000000000..f2ff1cf00 --- /dev/null +++ b/tests/functional/html/open_new_window.html @@ -0,0 +1,8 @@ + + + php-webdriver test page + + + open new window + + diff --git a/tests/functional/html/upload.html b/tests/functional/html/upload.html index ed03702d3..2eef0c026 100644 --- a/tests/functional/html/upload.html +++ b/tests/functional/html/upload.html @@ -1,10 +1,10 @@ - Upload a file + Upload a file -
- -
+
+ +
From f55c684703826a30d19e9bd3dd6567c833cc8c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 1 Jan 2017 21:40:41 +0100 Subject: [PATCH 068/600] Separate functional test that finds elemements --- tests/functional/FindElementTest.php | 100 ------------------ .../RemoteWebDriverFindElementTest.php | 63 +++++++++++ tests/functional/RemoteWebElementTest.php | 30 ++++++ tests/functional/WebDriverByTest.php | 64 +++++++++++ 4 files changed, 157 insertions(+), 100 deletions(-) delete mode 100644 tests/functional/FindElementTest.php create mode 100644 tests/functional/RemoteWebDriverFindElementTest.php create mode 100644 tests/functional/RemoteWebElementTest.php create mode 100644 tests/functional/WebDriverByTest.php diff --git a/tests/functional/FindElementTest.php b/tests/functional/FindElementTest.php deleted file mode 100644 index f479fc9bc..000000000 --- a/tests/functional/FindElementTest.php +++ /dev/null @@ -1,100 +0,0 @@ -driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Welcome to the facebook/php-webdriver testing page.', - $this->driver->findElement(WebDriverBy::id('welcome'))->getText() - ); - } - - public function testGetById() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Test by ID', - $this->driver->findElement(WebDriverBy::id('id_test'))->getText() - ); - } - - public function testGetByClassName() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Test by Class', - $this->driver->findElement(WebDriverBy::className('test_class'))->getText() - ); - } - - public function testGetByCssSelector() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Test by Class', - $this->driver->findElement(WebDriverBy::cssSelector('.test_class'))->getText() - ); - } - - public function testGetByLinkText() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Click here', - $this->driver->findElement(WebDriverBy::linkText('Click here'))->getText() - ); - } - - public function testGetByName() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Test Value', - $this->driver->findElement(WebDriverBy::name('test_name'))->getAttribute('value') - ); - } - - public function testGetByXpath() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Test Value', - $this->driver->findElement(WebDriverBy::xpath('//input[@name="test_name"]'))->getAttribute('value') - ); - } - - public function testGetByPartialLinkText() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Click here', - $this->driver->findElement(WebDriverBy::partialLinkText('Click'))->getText() - ); - } - - public function testGetByTagName() - { - $this->driver->get($this->getTestPath('index.html')); - $this->assertEquals( - 'Test Value', - $this->driver->findElement(WebDriverBy::tagName('input'))->getAttribute('value') - ); - } -} diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php new file mode 100644 index 000000000..64f7b8d9c --- /dev/null +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -0,0 +1,63 @@ +driver->get($this->getTestPath('index.html')); + + $this->setExpectedException(NoSuchElementException::class, 'Unable to locate element'); + $this->driver->findElement(WebDriverBy::id('not_existing')); + } + + public function testShouldFindElementIfExistsOnAPage() + { + $this->driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement(WebDriverBy::id('id_test')); + + $this->assertInstanceOf(RemoteWebElement::class, $element); + } + + public function testShouldReturnEmptyArrayIfElementsCannotBeFound() + { + $this->driver->get($this->getTestPath('index.html')); + + $elements = $this->driver->findElements(WebDriverBy::cssSelector('not_existing')); + + $this->assertInternalType('array', $elements); + $this->assertCount(0, $elements); + } + + public function testShouldFindMultipleElements() + { + $this->driver->get($this->getTestPath('index.html')); + + $elements = $this->driver->findElements(WebDriverBy::cssSelector('ul > li')); + + $this->assertInternalType('array', $elements); + $this->assertCount(3, $elements); + $this->assertContainsOnlyInstancesOf(RemoteWebElement::class, $elements); + } +} diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php new file mode 100644 index 000000000..1869671d4 --- /dev/null +++ b/tests/functional/RemoteWebElementTest.php @@ -0,0 +1,30 @@ +driver->get($this->getTestPath('index.html')); + $element = $this->driver->findElement(WebDriverBy::id('welcome')); + + $this->assertEquals( + 'Welcome to the facebook/php-webdriver testing page.', + $element->getText() + ); + } +} diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php new file mode 100644 index 000000000..4309836f6 --- /dev/null +++ b/tests/functional/WebDriverByTest.php @@ -0,0 +1,64 @@ +driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement($locator); + + $this->assertInstanceOf(RemoteWebElement::class, $element); + + if ($expectedText !== null) { + $this->assertEquals($expectedText, $element->getText()); + } + + if ($expectedAttributeValue !== null) { + $this->assertEquals($expectedAttributeValue, $element->getAttribute('value')); + } + } + + public function textElementsProvider() + { + return [ + 'id' => [WebDriverBy::id('id_test'), 'Test by ID'], + 'className' => [WebDriverBy::className('test_class'), 'Test by Class'], + 'cssSelector' => [WebDriverBy::cssSelector('.test_class'), 'Test by Class'], + 'linkText' => [WebDriverBy::linkText('Click here'), 'Click here'], + 'partialLinkText' => [WebDriverBy::partialLinkText('Click'), 'Click here'], + 'xpath' => [WebDriverBy::xpath('//input[@name="test_name"]'), '', 'Test Value'], + 'name' => [WebDriverBy::name('test_name'), '', 'Test Value'], + 'tagName' => [WebDriverBy::tagName('input'), '', 'Test Value'], + ]; + } +} From 3da2cc1527a143b8e93c2138794d0cebe6bdc115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 2 Jan 2017 02:13:45 +0100 Subject: [PATCH 069/600] Rewrite file upload functional tests to execute real upload against webserver --- .travis.yml | 2 + tests/functional/FileUploadTest.php | 48 ++++++++++++------- .../FileUploadTestFile.txt} | 0 tests/functional/WebDriverTestCase.php | 24 ++++++++-- tests/functional/html/upload.html | 10 ---- tests/functional/{html => web}/index.html | 4 +- .../{html => web}/open_new_window.html | 4 +- tests/functional/web/upload.html | 18 +++++++ tests/functional/web/upload.php | 29 +++++++++++ 9 files changed, 106 insertions(+), 33 deletions(-) rename tests/functional/{files/FileUploadTestCaseFile.txt => Fixtures/FileUploadTestFile.txt} (100%) delete mode 100644 tests/functional/html/upload.html rename tests/functional/{html => web}/index.html (87%) rename tests/functional/{html => web}/open_new_window.html (68%) create mode 100644 tests/functional/web/upload.html create mode 100644 tests/functional/web/upload.php diff --git a/.travis.yml b/.travis.yml index 21f11b4e5..b250e2d63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,12 +45,14 @@ before_script: # TODO: use this after upgrade to Selenium 3.0.2 #- /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.0.2.jar -log selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done + - php -S localhost:8000 -t tests/functional/web/ &>>php-server.log & script: - ./vendor/bin/phpunit after_script: - cat selenium.log + - cat php-server.log addons: firefox: "latest-esr" diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index 57ebff23c..e3b6be1d3 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -17,33 +17,47 @@ use Facebook\WebDriver\Remote\LocalFileDetector; -/** - * An example test case for php-webdriver. - * - * Try running it by - * '../vendor/phpunit/phpunit/phpunit.php ExampleTestCase.php' - */ class FileUploadTest extends WebDriverTestCase { - public function testFileUploading() + public function testShouldUploadAFile() { - $this->driver->get($this->getTestPath('upload.html')); - $file_input = $this->driver->findElement(WebDriverBy::id('upload')); - $file_input->setFileDetector(new LocalFileDetector()) - ->sendKeys(__DIR__ . '/files/FileUploadTestCaseFile.txt'); - $this->assertNotEquals($this->getFilePath(), $file_input->getAttribute('value')); + $this->driver->get($this->getTestPageUrl('upload.html')); + + $fileElement = $this->driver->findElement(WebDriverBy::name('upload')); + + $fileElement->setFileDetector(new LocalFileDetector()) + ->sendKeys($this->getTestFilePath()); + + $fileElement->submit(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::titleIs('File upload endpoint') + ); + + $uploadedFilesList = $this->driver->findElements(WebDriverBy::cssSelector('ul.uploaded-files li')); + $this->assertCount(1, $uploadedFilesList); + + $uploadedFileName = $this->driver->findElement(WebDriverBy::cssSelector('ul.uploaded-files li span.file-name')) + ->getText(); + $uploadedFileSize = $this->driver->findElement(WebDriverBy::cssSelector('ul.uploaded-files li span.file-size')) + ->getText(); + + $this->assertSame('FileUploadTestFile.txt', $uploadedFileName); + $this->assertSame('10', $uploadedFileSize); } - public function testUselessFileDetectorSendKeys() + public function xtestUselessFileDetectorSendKeys() { $this->driver->get($this->getTestPath('upload.html')); + $file_input = $this->driver->findElement(WebDriverBy::id('upload')); - $file_input->sendKeys($this->getFilePath()); - $this->assertEquals($this->getFilePath(), $file_input->getAttribute('value')); + $file_input->sendKeys($this->getTestFilePath()); + + $this->assertEquals($this->getTestFilePath(), $file_input->getAttribute('value')); } - private function getFilePath() + private function getTestFilePath() { - return __DIR__ . '/files/FileUploadTestCaseFile.txt'; + return __DIR__ . '/Fixtures/FileUploadTestFile.txt'; } } diff --git a/tests/functional/files/FileUploadTestCaseFile.txt b/tests/functional/Fixtures/FileUploadTestFile.txt similarity index 100% rename from tests/functional/files/FileUploadTestCaseFile.txt rename to tests/functional/Fixtures/FileUploadTestFile.txt diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 080a30bca..f44c70343 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -15,6 +15,7 @@ namespace Facebook\WebDriver; +use Facebook\WebDriver\Exception\NoSuchWindowException; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\WebDriverBrowserType; @@ -47,19 +48,34 @@ protected function setUp() protected function tearDown() { - if ($this->driver) { - $this->driver->quit(); + if ($this->driver->getCommandExecutor()) { + try { + $this->driver->quit(); + } catch (NoSuchWindowException $e) { + // browser may have died or is already closed + } } } /** - * Get the URL of the test html. + * Get the URL of the test html on filesystem. * * @param $path * @return string */ protected function getTestPath($path) { - return 'file:///' . __DIR__ . '/html/' . $path; + return 'file:///' . __DIR__ . '/web/' . $path; + } + + /** + * Get the URL of given test HTML on running webserver. + * + * @param string $path + * @return string + */ + protected function getTestPageUrl($path) + { + return 'http://localhost:8000/' . $path; } } diff --git a/tests/functional/html/upload.html b/tests/functional/html/upload.html deleted file mode 100644 index 2eef0c026..000000000 --- a/tests/functional/html/upload.html +++ /dev/null @@ -1,10 +0,0 @@ - - - Upload a file - - -
- -
- - diff --git a/tests/functional/html/index.html b/tests/functional/web/index.html similarity index 87% rename from tests/functional/html/index.html rename to tests/functional/web/index.html index 419b41ee2..139a25865 100644 --- a/tests/functional/html/index.html +++ b/tests/functional/web/index.html @@ -1,5 +1,7 @@ - + + + php-webdriver test page diff --git a/tests/functional/html/open_new_window.html b/tests/functional/web/open_new_window.html similarity index 68% rename from tests/functional/html/open_new_window.html rename to tests/functional/web/open_new_window.html index f2ff1cf00..b56e93d69 100644 --- a/tests/functional/html/open_new_window.html +++ b/tests/functional/web/open_new_window.html @@ -1,5 +1,7 @@ - + + + php-webdriver test page diff --git a/tests/functional/web/upload.html b/tests/functional/web/upload.html new file mode 100644 index 000000000..d02c5ed4b --- /dev/null +++ b/tests/functional/web/upload.html @@ -0,0 +1,18 @@ + + + + + Upload a file + + +
+

+ + +

+

+ +

+
+ + diff --git a/tests/functional/web/upload.php b/tests/functional/web/upload.php new file mode 100644 index 000000000..91a61bbcf --- /dev/null +++ b/tests/functional/web/upload.php @@ -0,0 +1,29 @@ + + + + + File upload endpoint + + + +File upload not detected'; +} elseif (isset($_FILES['upload']) && $_FILES['upload']['error'] == 4) { + echo '

Form was submitted but no file was selected for upload

'; +} else { + echo sprintf('

Received %d uploaded file(s)

', count($_FILES)); + echo '
    '; + foreach ($_FILES as $file) { + echo sprintf( + '
  • File name: %s, size: %d
  • ', + $file['name'], + $file['size'] + ); + } + echo '
'; +} +?> + + + From 6d385d71b1e705451fd07e3880c19f3b3d4e85f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 2 Jan 2017 03:44:31 +0100 Subject: [PATCH 070/600] Do not run tests on HHVM, as it doesn't support builtin webserver --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b250e2d63..b9b2fe6d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ php: - 5.6 - 7 - 7.1 - - hhvm matrix: include: From f718bfaf94af67d082d8374bd3a214d2606ce25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 2 Jan 2017 19:37:55 +0100 Subject: [PATCH 071/600] Add some clarifications about the library status in README --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8c3e2370a..bc3e9fbb0 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,15 @@ ## Description Php-webdriver library is PHP language binding for Selenium WebDriver, which allows you to control web browsers from PHP. -This WebDriver client aims to be as close as possible to bindings in other languages. -The concepts are very similar to the Java, .NET, Python and Ruby bindings for WebDriver. +This library is compatible with Selenium server version 2.x and 3.x. +It implements the [JsonWireProtocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol), which is currently supported +by the Selenium server and will also implement the [W3C WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) specification in the future. -This is new version of PHP client, rewritten from scratch starting 2013. -Using the old version? Check out Adam Goucher's fork of it at https://github.com/Element-34/php-webdriver +The concepts of this library are very similar to the "official" Java, .NET, Python and Ruby bindings from the +[Selenium project](https://github.com/SeleniumHQ/selenium/). + +**This is new version of PHP client, rewritten from scratch starting 2013.** +Using the old version? Check out [Adam Goucher's fork](https://github.com/Element-34/php-webdriver) of it. Looking for API documentation of php-webdriver? See http://facebook.github.io/php-webdriver/ From 8755ace212f55a783a5d50fb93e5d7d330121075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 00:22:00 +0100 Subject: [PATCH 072/600] Send code coverage reports to coveralls.io --- .coveralls.yml | 2 ++ .gitignore | 1 + .travis.yml | 13 ++++++++----- composer.json | 3 ++- logs/.gitkeep | 0 5 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 .coveralls.yml create mode 100644 logs/.gitkeep diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 000000000..8115fc995 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,2 @@ +coverage_clover: ./logs/coverage-clover.xml +json_path: ./logs/coveralls-upload.json diff --git a/.gitignore b/.gitignore index e2cc31fbb..42ef8b562 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ composer.lock vendor .php_cs.cache phpunit.xml +logs/ # generic files to ignore *.lock diff --git a/.travis.yml b/.travis.yml index b9b2fe6d3..d8674413c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,18 +40,21 @@ before_script: - if [ ! -f jar/selenium-server-standalone-2.53.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar; fi - if [ ! -f jar/htmlunit-driver-standalone-2.20.jar ]; then wget -q -t 3 -P jar https://github.com/SeleniumHQ/htmlunit-driver/releases/download/2.20/htmlunit-driver-standalone-2.20.jar; fi # Temporarily run HtmlUnit from standalone jar file (it was not part of Selenium server standalone in version 2.53) - - java -cp "jar/selenium-server-standalone-2.53.1.jar:jar/htmlunit-driver-standalone-2.20.jar" org.openqa.grid.selenium.GridLauncher -log selenium.log & + - java -cp "jar/selenium-server-standalone-2.53.1.jar:jar/htmlunit-driver-standalone-2.20.jar" org.openqa.grid.selenium.GridLauncher -log ./logs/selenium.log & # TODO: use this after upgrade to Selenium 3.0.2 #- /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.0.2.jar -log selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done - - php -S localhost:8000 -t tests/functional/web/ &>>php-server.log & + - php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & script: - - ./vendor/bin/phpunit + - ./vendor/bin/phpunit --coverage-clover ./logs/coverage-clover.xml after_script: - - cat selenium.log - - cat php-server.log + - cat ./logs/selenium.log + - cat ./logs/php-server.log + +after_success: + - travis_retry php vendor/bin/coveralls -v addons: firefox: "latest-esr" diff --git a/composer.json b/composer.json index a8eb267e0..55780368b 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "phpunit/phpunit": "4.6.* || ~5.0", "friendsofphp/php-cs-fixer": "^1.11", "squizlabs/php_codesniffer": "^2.6", - "php-mock/php-mock-phpunit": "^1.1" + "php-mock/php-mock-phpunit": "^1.1", + "satooshi/php-coveralls": "^1.0" }, "suggest": { "phpdocumentor/phpdocumentor": "2.*" diff --git a/logs/.gitkeep b/logs/.gitkeep new file mode 100644 index 000000000..e69de29bb From 5e031e7bfde975e9a1b8b124c5a8ddf5676ed396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 00:15:35 +0100 Subject: [PATCH 073/600] Add lowest-dependencies Travis build --- .travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d8674413c..3710d83da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,16 +3,19 @@ language: php php: - 5.5 - 5.6 - - 7 + - 7.0 - 7.1 matrix: include: # Add build to run tests against Firefox (other runs are agains HtmlUnit by default) - - php: 7 + - php: 7.0 env: BROWSER_NAME="firefox" + # Build with lowest possible dependencies + - php: 7.0 + env: dependencies="--prefer-lowest" # Add PHP 7 build to check codestyle only in PHP 7 build - - php: 7 + - php: 7.0 env: CHECK_CODESTYLE=1 before_script: ~ script: @@ -32,7 +35,7 @@ before_install: - travis_retry composer self-update install: - - travis_retry composer install --no-interaction + - travis_retry composer update --no-interaction $dependencies before_script: - sh -e /etc/init.d/xvfb start From a583ff49e62241b41cc285893fe7344134628938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 18 Dec 2016 00:03:41 +0100 Subject: [PATCH 074/600] Support required capabilities --- lib/Remote/RemoteWebDriver.php | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index d06dc2e36..abc27ccb5 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -63,8 +63,9 @@ protected function __construct() * @param DesiredCapabilities|array $desired_capabilities The desired capabilities * @param int|null $connection_timeout_in_ms * @param int|null $request_timeout_in_ms - * @param string|null $http_proxy The proxy to tunnel requests through + * @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through * @param int|null $http_proxy_port + * @param DesiredCapabilities $required_capabilities The required capabilities * @return RemoteWebDriver */ public static function create( @@ -73,15 +74,12 @@ public static function create( $connection_timeout_in_ms = null, $request_timeout_in_ms = null, $http_proxy = null, - $http_proxy_port = null + $http_proxy_port = null, + DesiredCapabilities $required_capabilities = null ) { $selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url); - // Passing DesiredCapabilities as $desired_capabilities is encouraged but - // array is also accepted for legacy reason. - if ($desired_capabilities instanceof DesiredCapabilities) { - $desired_capabilities = $desired_capabilities->toArray(); - } + $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities); $executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port); if ($connection_timeout_in_ms !== null) { @@ -91,10 +89,17 @@ public static function create( $executor->setRequestTimeout($request_timeout_in_ms); } + if ($required_capabilities !== null) { + // TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities. + // This will probably change in future with the W3C WebDriver spec, but is the only way how to pass these + // values now. + $desired_capabilities->setCapability('requiredCapabilities', $required_capabilities->toArray()); + } + $command = new WebDriverCommand( null, DriverCommand::NEW_SESSION, - ['desiredCapabilities' => $desired_capabilities] + ['desiredCapabilities' => $desired_capabilities->toArray()] ); $response = $executor->execute($command); @@ -106,6 +111,26 @@ public static function create( return $driver; } + /** + * Cast legacy types (array or null) to DesiredCapabilities object. To be removed in future when instance of + * DesiredCapabilities will be required. + * + * @param array|DesiredCapabilities|null $desired_capabilities + * @return DesiredCapabilities + */ + protected static function castToDesiredCapabilitiesObject($desired_capabilities = null) + { + if ($desired_capabilities === null) { + return new DesiredCapabilities(); + } + + if (is_array($desired_capabilities)) { + return new DesiredCapabilities($desired_capabilities); + } + + return $desired_capabilities; + } + /** * [Experimental] Construct the RemoteWebDriver by an existing session. * From 86a0b18b8f2abec691a59930b69b7d4c96c325ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 00:52:44 +0100 Subject: [PATCH 075/600] Add issue template --- ISSUE_TEMPLATE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..3eef8cde7 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,21 @@ +### What are you trying to achieve? (Expected behavior) + + +### What do you get instead? (Actual behavior) + + +### How could the issue be reproduced? (Steps to reproduce) + + +```php +// You can insert your PHP code here (or remove this block if it is not relevant for the issue). +``` + +### Details + + +* Php-webdriver version: +* PHP version: +* Selenium server version: +* Operating system: +* Browser used + version: From 1ba81ee6aa2e175a76f8d8d0ca512e888cd5cd1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 01:22:37 +0100 Subject: [PATCH 076/600] Add functional test for WebDriver creation --- .../functional/RemoteWebDriverCreateTest.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/functional/RemoteWebDriverCreateTest.php diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php new file mode 100644 index 000000000..4f05a4319 --- /dev/null +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -0,0 +1,63 @@ +driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities, 10000, 13370); + + $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); + + $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); + $this->assertSame($this->serverUrl, $this->driver->getCommandExecutor()->getAddressOfRemoteServer()); + + $this->assertInternalType('string', $this->driver->getSessionID()); + $this->assertNotEmpty($this->driver->getSessionID()); + + $returnedCapabilities = $this->driver->getCapabilities(); + $this->assertInstanceOf(WebDriverCapabilities::class, $returnedCapabilities); + $this->assertSame($this->desiredCapabilities->getBrowserName(), $returnedCapabilities->getBrowserName()); + } + + public function testShouldCreateWebDriverWithRequiredCapabilities() + { + $requiredCapabilities = new DesiredCapabilities(); + + $this->driver = RemoteWebDriver::create( + $this->serverUrl, + $this->desiredCapabilities, + null, + null, + null, + null, + $requiredCapabilities + ); + + $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); + } +} From 6c155c801ccc6fe3b1efb4ab51147da3e790d834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 00:10:37 +0100 Subject: [PATCH 077/600] Define @covers for functional tests, to cover just what is actually tested --- CHANGELOG.md | 4 +- lib/Chrome/ChromeDriver.php | 7 +-- lib/Remote/HttpCommandExecutor.php | 2 +- lib/Remote/RemoteWebDriver.php | 59 ++++++++++++++----- lib/Remote/Service/DriverCommandExecutor.php | 3 +- lib/WebDriverCommandExecutor.php | 3 +- tests/functional/FileUploadTest.php | 4 ++ .../RemoteWebDriverFindElementTest.php | 3 + tests/functional/RemoteWebDriverTest.php | 3 + tests/functional/RemoteWebElementTest.php | 3 + tests/functional/WebDriverByTest.php | 1 + tests/functional/WebDriverTestCase.php | 12 +++- 12 files changed, 77 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fadf18bf8..137452511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve poratbility -- Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class +- Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class +- Deprecated `setSessionID()` and `setCommandExecutor()` methods of `RemoteWebDriver` class; these values should be immutable and thus passed only via constructor. +- Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. ## 1.2.0 - 2016-10-14 - Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 32ddf8f85..7aac128e4 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -33,9 +33,8 @@ public static function start(DesiredCapabilities $desired_capabilities = null, C $service = ChromeDriverService::createDefaultService(); } $executor = new DriverCommandExecutor($service); - $driver = new static(); - $driver->setCommandExecutor($executor) - ->startSession($desired_capabilities); + $driver = new static($executor, null, $desired_capabilities); + $driver->startSession($desired_capabilities); return $driver; } @@ -50,7 +49,7 @@ public function startSession(DesiredCapabilities $desired_capabilities) ] ); $response = $this->executor->execute($command); - $this->setSessionID($response->getSessionID()); + $this->sessionID = $response->getSessionID(); } /** diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 11b53536a..85045855e 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -224,7 +224,7 @@ public function setRequestTimeout($timeout_in_ms) * @param WebDriverCommand $command * * @throws WebDriverException - * @return mixed + * @return WebDriverResponse */ public function execute(WebDriverCommand $command) { diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index abc27ccb5..dd1be325a 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -19,6 +19,7 @@ use Facebook\WebDriver\JavaScriptExecutor; use Facebook\WebDriver\WebDriver; use Facebook\WebDriver\WebDriverBy; +use Facebook\WebDriver\WebDriverCapabilities; use Facebook\WebDriver\WebDriverCommandExecutor; use Facebook\WebDriver\WebDriverElement; use Facebook\WebDriver\WebDriverNavigation; @@ -31,6 +32,11 @@ class RemoteWebDriver implements WebDriver, JavaScriptExecutor * @var HttpCommandExecutor */ protected $executor; + /** + * @var WebDriverCapabilities + */ + protected $capabilities; + /** * @var string */ @@ -52,8 +58,17 @@ class RemoteWebDriver implements WebDriver, JavaScriptExecutor */ protected $executeMethod; - protected function __construct() - { + protected function __construct( + HttpCommandExecutor $commandExecutor, + $sessionId, + WebDriverCapabilities $capabilities = null + ) { + $this->executor = $commandExecutor; + $this->sessionID = $sessionId; + + if ($capabilities !== null) { + $this->capabilities = $capabilities; + } } /** @@ -61,10 +76,10 @@ protected function __construct() * * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param DesiredCapabilities|array $desired_capabilities The desired capabilities - * @param int|null $connection_timeout_in_ms - * @param int|null $request_timeout_in_ms + * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server + * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server * @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through - * @param int|null $http_proxy_port + * @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through * @param DesiredCapabilities $required_capabilities The required capabilities * @return RemoteWebDriver */ @@ -103,10 +118,9 @@ public static function create( ); $response = $executor->execute($command); + $returnedCapabilities = new DesiredCapabilities($response->getValue()); - $driver = new static(); - $driver->setSessionID($response->getSessionID()) - ->setCommandExecutor($executor); + $driver = new static($executor, $response->getSessionID(), $returnedCapabilities); return $driver; } @@ -134,9 +148,8 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities /** * [Experimental] Construct the RemoteWebDriver by an existing session. * - * This constructor can boost the performance a lot by reusing the same - * browser for the whole test suite. You do not have to pass the desired - * capabilities because the session was created before. + * This constructor can boost the performance a lot by reusing the same browser for the whole test suite. + * You cannot the desired capabilities because the session was created before. * * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param string $session_id The existing session id @@ -144,11 +157,9 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities */ public static function createBySessionID($session_id, $selenium_server_url = 'http://localhost:4444/wd/hub') { - $driver = new static(); - $driver->setSessionID($session_id) - ->setCommandExecutor(new HttpCommandExecutor($selenium_server_url)); + $executor = new HttpCommandExecutor($selenium_server_url); - return $driver; + return new static($executor, $session_id); } /** @@ -493,6 +504,9 @@ protected function newElement($id) /** * Set the command executor of this RemoteWebdriver * + * @deprecated To be removed in the future. Executor should be passed in the constructor. + * @internal + * @codeCoverageIgnore * @param WebDriverCommandExecutor $executor * @return RemoteWebDriver */ @@ -516,6 +530,9 @@ public function getCommandExecutor() /** * Set the session id of the RemoteWebDriver. * + * @deprecated To be removed in the future. Session ID should be passed in the constructor. + * @internal + * @codeCoverageIgnore * @param string $session_id * @return RemoteWebDriver */ @@ -529,13 +546,23 @@ public function setSessionID($session_id) /** * Get current selenium sessionID * - * @return string sessionID + * @return string */ public function getSessionID() { return $this->sessionID; } + /** + * Get capabilities of the RemoteWebDriver. + * + * @return WebDriverCapabilities + */ + public function getCapabilities() + { + return $this->capabilities; + } + /** * Returns a list of the currently active sessions. * diff --git a/lib/Remote/Service/DriverCommandExecutor.php b/lib/Remote/Service/DriverCommandExecutor.php index 59125833b..28cc5e438 100644 --- a/lib/Remote/Service/DriverCommandExecutor.php +++ b/lib/Remote/Service/DriverCommandExecutor.php @@ -19,6 +19,7 @@ use Facebook\WebDriver\Remote\DriverCommand; use Facebook\WebDriver\Remote\HttpCommandExecutor; use Facebook\WebDriver\Remote\WebDriverCommand; +use Facebook\WebDriver\Remote\WebDriverResponse; /** * A HttpCommandExecutor that talks to a local driver service instead of @@ -42,7 +43,7 @@ public function __construct(DriverService $service) * * @throws WebDriverException * @throws \Exception - * @return mixed + * @return WebDriverResponse */ public function execute(WebDriverCommand $command) { diff --git a/lib/WebDriverCommandExecutor.php b/lib/WebDriverCommandExecutor.php index 00357c6e7..0a50ccdde 100644 --- a/lib/WebDriverCommandExecutor.php +++ b/lib/WebDriverCommandExecutor.php @@ -16,6 +16,7 @@ namespace Facebook\WebDriver; use Facebook\WebDriver\Remote\WebDriverCommand; +use Facebook\WebDriver\Remote\WebDriverResponse; /** * Interface for all command executor. @@ -25,7 +26,7 @@ interface WebDriverCommandExecutor /** * @param WebDriverCommand $command * - * @return mixed + * @return WebDriverResponse */ public function execute(WebDriverCommand $command); } diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index e3b6be1d3..e8878e642 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -17,6 +17,10 @@ use Facebook\WebDriver\Remote\LocalFileDetector; +/** + * @covers Facebook\WebDriver\Remote\LocalFileDetector + * @covers Facebook\WebDriver\Remote\RemoteWebElement + */ class FileUploadTest extends WebDriverTestCase { public function testShouldUploadAFile() diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 64f7b8d9c..751b0310e 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -20,6 +20,9 @@ /** * Tests for findElement() and findElements() method of RemoteWebDriver. + * @covers Facebook\WebDriver\Remote\RemoteWebDriver + * @covers Facebook\WebDriver\Exception\WebDriverException + * @covers Facebook\WebDriver\Exception\NoSuchElementException */ class RemoteWebDriverFindElementTest extends WebDriverTestCase { diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 0f9691c96..1ce4c9570 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -19,6 +19,9 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\WebDriverBrowserType; +/** + * @covers Facebook\WebDriver\Remote\RemoteWebDriver + */ class RemoteWebDriverTest extends WebDriverTestCase { public function testShouldGetPageTitle() diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 1869671d4..e176d4189 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -15,6 +15,9 @@ namespace Facebook\WebDriver; +/** + * @covers Facebook\WebDriver\Remote\RemoteWebElement + */ class RemoteWebElementTest extends WebDriverTestCase { public function testShouldGetText() diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php index 4309836f6..da614f69b 100644 --- a/tests/functional/WebDriverByTest.php +++ b/tests/functional/WebDriverByTest.php @@ -19,6 +19,7 @@ /** * Tests for locator strategies provided by WebDriverBy. + * @covers Facebook\WebDriver\WebDriverBy */ class WebDriverByTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index f44c70343..8c2fd4b8d 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -25,6 +25,11 @@ */ class WebDriverTestCase extends \PHPUnit_Framework_TestCase { + /** @var bool Indicate whether WebDriver should be created on setUp */ + protected $createWebDriver = true; + /** @var string */ + protected $serverUrl = 'http://localhost:4444/wd/hub'; + /** @var RemoteWebDriver $driver */ protected $driver; /** @var DesiredCapabilities */ @@ -33,7 +38,6 @@ class WebDriverTestCase extends \PHPUnit_Framework_TestCase protected function setUp() { $this->desiredCapabilities = new DesiredCapabilities(); - $serverUrl = 'http://localhost:4444/wd/hub'; if (getenv('BROWSER_NAME')) { $browserName = getenv('BROWSER_NAME'); @@ -43,12 +47,14 @@ protected function setUp() $this->desiredCapabilities->setBrowserName($browserName); - $this->driver = RemoteWebDriver::create($serverUrl, $this->desiredCapabilities); + if ($this->createWebDriver) { + $this->driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities); + } } protected function tearDown() { - if ($this->driver->getCommandExecutor()) { + if ($this->driver instanceof RemoteWebDriver && $this->driver->getCommandExecutor()) { try { $this->driver->quit(); } catch (NoSuchWindowException $e) { From 3e2413d87e0ec88bed56c99f485df84d3c6cad03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 00:35:35 +0100 Subject: [PATCH 078/600] Update changelog --- CHANGELOG.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 137452511..c3d9f1f42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,31 +2,32 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased -- `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve poratbility -- Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class +- `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve portability. +- Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class. - Deprecated `setSessionID()` and `setCommandExecutor()` methods of `RemoteWebDriver` class; these values should be immutable and thus passed only via constructor. - Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. +- Added option to pass required capabilities when creating `RemoteWebDriver`. (So far only desired capabilities were supported.) ## 1.2.0 - 2016-10-14 -- Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported) -- Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible -- PHP version at least 5.5 is required -- Fixed incompatibility with Appium, caused by redundant params present in requests to Selenium server +- Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported). +- Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible. +- PHP version at least 5.5 is required. +- Fixed incompatibility with Appium, caused by redundant params present in requests to Selenium server. ## 1.1.3 - 2016-08-10 -- Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file -- Comply codestyle with [PSR-2](http://www.php-fig.org/psr/psr-2/) +- Fixed FirefoxProfile to support installation of extensions with custom namespace prefix in their manifest file. +- Comply codestyle with [PSR-2](http://www.php-fig.org/psr/psr-2/). ## 1.1.2 - 2016-06-04 -- Added ext-curl to composer.json -- Added CHANGELOG.md -- Added CONTRIBUTING.md with information and rules for contributors +- Added ext-curl to composer.json. +- Added CHANGELOG.md. +- Added CONTRIBUTING.md with information and rules for contributors. ## 1.1.1 - 2015-12-31 -- Fixed strict standards error in `ChromeDriver` -- Added unit tests for `WebDriverCommand` and `DesiredCapabilities` -- Fixed retrieving temporary path name in `FirefoxDriver` when `open_basedir` restriction is in effect +- Fixed strict standards error in `ChromeDriver`. +- Added unit tests for `WebDriverCommand` and `DesiredCapabilities`. +- Fixed retrieving temporary path name in `FirefoxDriver` when `open_basedir` restriction is in effect. ## 1.1.0 - 2015-12-08 -- FirefoxProfile improved - added possibility to set RDF file and to add datas for extensions -- Fixed setting 0 second timeout of `WebDriverWait` +- FirefoxProfile improved - added possibility to set RDF file and to add datas for extensions. +- Fixed setting 0 second timeout of `WebDriverWait`. From 718d404e0a949afea74cde12a65acdcdeb1d8b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 01:18:51 +0100 Subject: [PATCH 079/600] Refactor WebDriverByTest data provider to not the repeat same code --- tests/functional/WebDriverByTest.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php index da614f69b..753790248 100644 --- a/tests/functional/WebDriverByTest.php +++ b/tests/functional/WebDriverByTest.php @@ -25,18 +25,21 @@ class WebDriverByTest extends WebDriverTestCase { /** * @dataProvider textElementsProvider - * @param WebDriverBy $locator + * @param $webDriverByLocatorMethod + * @param $webDriverByLocatorValue * @param string $expectedText * @param string $expectedAttributeValue */ public function testShouldFindTextElementByLocator( - WebDriverBy $locator, + $webDriverByLocatorMethod, + $webDriverByLocatorValue, $expectedText = null, $expectedAttributeValue = null ) { $this->driver->get($this->getTestPath('index.html')); - $element = $this->driver->findElement($locator); + $by = call_user_func([WebDriverBy::class, $webDriverByLocatorMethod], $webDriverByLocatorValue); + $element = $this->driver->findElement($by); $this->assertInstanceOf(RemoteWebElement::class, $element); @@ -52,14 +55,14 @@ public function testShouldFindTextElementByLocator( public function textElementsProvider() { return [ - 'id' => [WebDriverBy::id('id_test'), 'Test by ID'], - 'className' => [WebDriverBy::className('test_class'), 'Test by Class'], - 'cssSelector' => [WebDriverBy::cssSelector('.test_class'), 'Test by Class'], - 'linkText' => [WebDriverBy::linkText('Click here'), 'Click here'], - 'partialLinkText' => [WebDriverBy::partialLinkText('Click'), 'Click here'], - 'xpath' => [WebDriverBy::xpath('//input[@name="test_name"]'), '', 'Test Value'], - 'name' => [WebDriverBy::name('test_name'), '', 'Test Value'], - 'tagName' => [WebDriverBy::tagName('input'), '', 'Test Value'], + 'id' => ['id', 'id_test', 'Test by ID'], + 'className' => ['className', 'test_class', 'Test by Class'], + 'cssSelector' => ['cssSelector', '.test_class', 'Test by Class'], + 'linkText' => ['linkText', 'Click here', 'Click here'], + 'partialLinkText' => ['partialLinkText', 'Click', 'Click here'], + 'xpath' => ['xpath', '//input[@name="test_name"]', '', 'Test Value'], + 'name' => ['name', 'test_name', '', 'Test Value'], + 'tagName' => ['tagName', 'input', '', 'Test Value'], ]; } } From 702f5e287b6386462e131e0f9ccbb7dea8d1e14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 02:50:32 +0100 Subject: [PATCH 080/600] Fix coveralls reporting --- .travis.yml | 2 ++ phpunit.xml.dist | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3710d83da..7c0cd3e77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,8 @@ matrix: script: - ./vendor/bin/php-cs-fixer fix --diff --dry-run - ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/ + after_script: ~ + after_success: ~ env: global: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 06dee9c0f..894ba470a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -23,4 +23,10 @@ tests/functional + + + + ./lib + + From 60bf22af015e083c1ab08d9beaad163ed5ea8229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 16 Dec 2016 14:54:11 +0100 Subject: [PATCH 081/600] Add tests for part of expected conditions --- lib/WebDriverExpectedCondition.php | 80 +++---- tests/unit/WebDriverExpectedConditionTest.php | 210 ++++++++++++++++++ 2 files changed, 245 insertions(+), 45 deletions(-) create mode 100644 tests/unit/WebDriverExpectedConditionTest.php diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index b7cd53204..f82255845 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -78,8 +78,8 @@ function (WebDriver $driver) use ($title) { } /** - * An expectation for checking that an element is present on the DOM of a - * page. This does not necessarily mean that the element is visible. + * An expectation for checking that an element is present on the DOM of a page. + * This does not necessarily mean that the element is visible. * * @param WebDriverBy $by The locator used to find the element. * @return WebDriverExpectedCondition The element which is located. @@ -94,9 +94,25 @@ function (WebDriver $driver) use ($by) { } /** - * An expectation for checking that an element is present on the DOM of a page - * and visible. Visibility means that the element is not only displayed but - * also has a height and width that is greater than 0. + * An expectation for checking that there is at least one element present on a web page. + * + * @param WebDriverBy $by The locator used to find the element. + * @return WebDriverExpectedCondition An array of WebDriverElements once they are located. + */ + public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) + { + return new static( + function (WebDriver $driver) use ($by) { + $elements = $driver->findElements($by); + + return count($elements) > 0 ? $elements : null; + } + ); + } + + /** + * An expectation for checking that an element is present on the DOM of a page and visible. + * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverBy $by The locator used to find the element. * @return WebDriverExpectedCondition The element which is located and visible. @@ -117,9 +133,8 @@ function (WebDriver $driver) use ($by) { } /** - * An expectation for checking that an element, known to be present on the DOM - * of a page, is visible. Visibility means that the element is not only - * displayed but also has a height and width that is greater than 0. + * An expectation for checking that an element, known to be present on the DOM of a page, is visible. + * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverElement $element The element to be checked. * @return WebDriverExpectedCondition The same WebDriverElement once it is visible. @@ -134,30 +149,11 @@ function () use ($element) { } /** - * An expectation for checking that there is at least one element present on a - * web page. - * - * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition An array of WebDriverElements once they are located. - */ - public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) - { - return new static( - function (WebDriver $driver) use ($by) { - $elements = $driver->findElements($by); - - return count($elements) > 0 ? $elements : null; - } - ); - } - - /** - * An expectation for checking if the given text is present in the specified - * element. + * An expectation for checking if the given text is present in the specified element. * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. - * @return bool WebDriverExpectedCondition Whether the text is presented. + * @return bool WebDriverExpectedCondition Whether the text is present. */ public static function textToBePresentInElement(WebDriverBy $by, $text) { @@ -175,8 +171,7 @@ function (WebDriver $driver) use ($by, $text) { } /** - * An expectation for checking if the given text is present in the specified - * elements value attribute. + * An expectation for checking if the given text is present in the specified elements value attribute. * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element value. @@ -198,8 +193,7 @@ function (WebDriver $driver) use ($by, $text) { } /** - * Expectation for checking if iFrame exists. - * If iFrame exists switches driver's focus to the iFrame + * Expectation for checking if iFrame exists. If iFrame exists switches driver's focus to the iFrame. * * @param string $frame_locator The locator used to find the iFrame * expected to be either the id or name value of the i/frame @@ -220,8 +214,7 @@ function (WebDriver $driver) use ($frame_locator) { } /** - * An expectation for checking that an element is either invisible or not - * present on the DOM. + * An expectation for checking that an element is either invisible or not present on the DOM. * * @param WebDriverBy $by The locator used to find the element. * @return bool WebDriverExpectedCondition Whether there is no element located. @@ -231,7 +224,7 @@ public static function invisibilityOfElementLocated(WebDriverBy $by) return new static( function (WebDriver $driver) use ($by) { try { - return !($driver->findElement($by)->isDisplayed()); + return !$driver->findElement($by)->isDisplayed(); } catch (NoSuchElementException $e) { return true; } catch (StaleElementReferenceException $e) { @@ -242,8 +235,7 @@ function (WebDriver $driver) use ($by) { } /** - * An expectation for checking that an element with text is either invisible - * or not present on the DOM. + * An expectation for checking that an element with text is either invisible or not present on the DOM. * * @param WebdriverBy $by The locator used to find the element. * @param string $text The text of the element. @@ -265,8 +257,7 @@ function (WebDriver $driver) use ($by, $text) { } /** - * An expectation for checking an element is visible and enabled such that you - * can click it. + * An expectation for checking an element is visible and enabled such that you can click it. * * @param WebDriverBy $by The locator used to find the element * @return WebDriverExpectedCondition The WebDriverElement @@ -320,11 +311,10 @@ function () use ($element) { /** * Wrapper for a condition, which allows for elements to update by redrawing. * - * This works around the problem of conditions which have two parts: find an - * element and then check for some condition on it. For these conditions it is - * possible that an element is located and then subsequently it is redrawn on - * the client. When this happens a StaleElementReferenceException is thrown - * when the second part of the condition is checked. + * This works around the problem of conditions which have two parts: find an element and then check for some + * condition on it. For these conditions it is possible that an element is located and then subsequently it is + * redrawn on the client. When this happens a StaleElementReferenceException is thrown when the second part of + * the condition is checked. * * @param WebDriverExpectedCondition $condition The condition wrapped. * @return WebDriverExpectedCondition The return value of the getApply() of the given condition. diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php new file mode 100644 index 000000000..85997939e --- /dev/null +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -0,0 +1,210 @@ +driverMock = $this + ->getMockBuilder(RemoteWebDriver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->wait = new WebDriverWait($this->driverMock, 1, 1); + } + + public function testShouldDetectTitleIsCondition() + { + $this->driverMock->expects($this->any()) + ->method('getTitle') + ->willReturnOnConsecutiveCalls('old', 'oldwithnew', 'new'); + + $condition = WebDriverExpectedCondition::titleIs('new'); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + + public function testShouldDetectTitleContainsCondition() + { + $this->driverMock->expects($this->any()) + ->method('getTitle') + ->willReturnOnConsecutiveCalls('old', 'oldwithnew', 'new'); + + $condition = WebDriverExpectedCondition::titleContains('new'); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + + public function testShouldDetectPresenceOfElementLocatedCondition() + { + $element = new RemoteWebElement(new RemoteExecuteMethod($this->driverMock), 'id'); + + $this->driverMock->expects($this->at(0)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willThrowException(new NoSuchElementException('')); + + $this->driverMock->expects($this->at(1)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $condition = WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('.foo')); + + $this->assertSame($element, $this->wait->until($condition)); + } + + public function testShouldDetectPresenceOfAllElementsLocatedByCondition() + { + $element = $this->createRemoteWebElementMock(); + + $this->driverMock->expects($this->at(0)) + ->method('findElements') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn([]); + + $this->driverMock->expects($this->at(1)) + ->method('findElements') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn([$element]); + + $condition = WebDriverExpectedCondition::presenceOfAllElementsLocatedBy(WebDriverBy::cssSelector('.foo')); + + $this->assertSame([$element], $this->wait->until($condition)); + } + + public function testShouldDetectVisibilityOfElementLocatedCondition() + { + // Set-up the consecutive calls to apply() as follows: + // Call #1: throws NoSuchElementException + // Call #2: return Element, but isDisplayed will throw StaleElementReferenceException + // Call #3: return Element, but isDisplayed will return false + // Call #4: return Element, isDisplayed will true and condition will match + + $element = $this->createRemoteWebElementMock(); + $element->expects($this->at(0)) + ->method('isDisplayed') + ->willThrowException(new StaleElementReferenceException('')); + + $element->expects($this->at(1)) + ->method('isDisplayed') + ->willReturn(false); + + $element->expects($this->at(2)) + ->method('isDisplayed') + ->willReturn(true); + + $this->driverMock->expects($this->at(0)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willThrowException(new NoSuchElementException('')); + + $this->driverMock->expects($this->at(1)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $this->driverMock->expects($this->at(2)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $this->driverMock->expects($this->at(3)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $condition = WebDriverExpectedCondition::visibilityOfElementLocated(WebDriverBy::cssSelector('.foo')); + + $this->assertSame($element, $this->wait->until($condition)); + } + + public function testShouldDetectVisibilityOfCondition() + { + $element = $this->createRemoteWebElementMock(); + $element->expects($this->at(0)) + ->method('isDisplayed') + ->willReturn(false); + + $element->expects($this->at(1)) + ->method('isDisplayed') + ->willReturn(true); + + $condition = WebDriverExpectedCondition::visibilityOf($element); + + $this->assertSame($element, $this->wait->until($condition)); + } + + public function testShouldDetectTextToBePresentInElementCondition() + { + // Set-up the consecutive calls to apply() as follows: + // Call #1: throws NoSuchElementException + // Call #2: return Element, but getText returns an old text + // Call #3: return Element, but getText will throw StaleElementReferenceException + // Call #4: return Element, getText will return new text and condition will match + + $element = $this->createRemoteWebElementMock(); + $element->expects($this->at(0)) + ->method('getText') + ->willReturn('this is an old text'); + + $element->expects($this->at(1)) + ->method('getText') + ->willThrowException(new StaleElementReferenceException('')); + + $element->expects($this->at(2)) + ->method('getText') + ->willReturn('this is a new text'); + + $this->setupDriverToReturnElementAfterAnException($element, 4); + + $condition = WebDriverExpectedCondition::textToBePresentInElement(WebDriverBy::cssSelector('.foo'), 'new'); + + $this->assertTrue($this->wait->until($condition)); + } + + /** + * @todo Replace with createMock() once PHP 5.5 support is dropped + * @return \PHPUnit_Framework_MockObject_MockObject|RemoteWebElement + */ + private function createRemoteWebElementMock() + { + return $this->getMockBuilder(RemoteWebElement::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->getMock(); + } +} From 3d96ee5e36bc85e47afaf904da7cae3a64594aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 16 Dec 2016 16:07:58 +0100 Subject: [PATCH 082/600] Add titleMatches condition to test against regexp --- lib/WebDriverExpectedCondition.php | 15 +++++++++++++++ tests/unit/WebDriverExpectedConditionTest.php | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index f82255845..45ef86f50 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -77,6 +77,21 @@ function (WebDriver $driver) use ($title) { ); } + /** + * An expectation for checking current page title matches the given regular expression. + * + * @param string $titleRegexp The regular expression to test against. + * @return bool WebDriverExpectedCondition True when in title, false otherwise. + */ + public static function titleMatches($titleRegexp) + { + return new static( + function (WebDriver $driver) use ($titleRegexp) { + return (bool) preg_match($titleRegexp, $driver->getTitle()); + } + ); + } + /** * An expectation for checking that an element is present on the DOM of a page. * This does not necessarily mean that the element is visible. diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index 85997939e..a8d078e7a 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -67,6 +67,19 @@ public function testShouldDetectTitleContainsCondition() $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); } + public function testShouldDetectTitleMatchesCondition() + { + $this->driverMock->expects($this->any()) + ->method('getTitle') + ->willReturnOnConsecutiveCalls('non-matching', 'matching-not', 'matching-123'); + + $condition = WebDriverExpectedCondition::titleMatches('/matching-\d{3}/'); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + public function testShouldDetectPresenceOfElementLocatedCondition() { $element = new RemoteWebElement(new RemoteExecuteMethod($this->driverMock), 'id'); From b4281e53344a58d7411aa3e161fdeaf3446dd4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 17 Dec 2016 17:16:38 +0100 Subject: [PATCH 083/600] Add new elementTextIs and elementTextMatches conditions --- lib/WebDriverExpectedCondition.php | 42 ++++++++ tests/unit/WebDriverExpectedConditionTest.php | 102 ++++++++++++++---- 2 files changed, 125 insertions(+), 19 deletions(-) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 45ef86f50..f2e75d1a2 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -165,6 +165,7 @@ function () use ($element) { /** * An expectation for checking if the given text is present in the specified element. + * To check exact text match use elementTextIs() condition. * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. @@ -185,6 +186,47 @@ function (WebDriver $driver) use ($by, $text) { ); } + /** + * An expectation for checking if the given text exactly equals the text in specified element. + * To check only partial substring of the text use textToBePresentInElement() condition. + * + * @param WebDriverBy $by The locator used to find the element. + * @param string $text The expected text of the element. + * @return bool WebDriverExpectedCondition True when element has text value equal to given one + */ + public static function elementTextIs(WebDriverBy $by, $text) + { + return new static( + function (WebDriver $driver) use ($by, $text) { + try { + return $driver->findElement($by)->getText() == $text; + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + + /** + * An expectation for checking if the given regular expression matches the text in specified element. + * + * @param WebDriverBy $by The locator used to find the element. + * @param string $regexp The regular expression to test against. + * @return bool WebDriverExpectedCondition True when element has text value equal to given one + */ + public static function elementTextMatches(WebDriverBy $by, $regexp) + { + return new static( + function (WebDriver $driver) use ($by, $regexp) { + try { + return (bool) preg_match($regexp, $driver->findElement($by)->getText()); + } catch (StaleElementReferenceException $e) { + return null; + } + } + ); + } + /** * An expectation for checking if the given text is present in the specified elements value attribute. * diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index a8d078e7a..fda958486 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -139,25 +139,7 @@ public function testShouldDetectVisibilityOfElementLocatedCondition() ->method('isDisplayed') ->willReturn(true); - $this->driverMock->expects($this->at(0)) - ->method('findElement') - ->with($this->isInstanceOf(WebDriverBy::class)) - ->willThrowException(new NoSuchElementException('')); - - $this->driverMock->expects($this->at(1)) - ->method('findElement') - ->with($this->isInstanceOf(WebDriverBy::class)) - ->willReturn($element); - - $this->driverMock->expects($this->at(2)) - ->method('findElement') - ->with($this->isInstanceOf(WebDriverBy::class)) - ->willReturn($element); - - $this->driverMock->expects($this->at(3)) - ->method('findElement') - ->with($this->isInstanceOf(WebDriverBy::class)) - ->willReturn($element); + $this->setupDriverToReturnElementAfterAnException($element, 4); $condition = WebDriverExpectedCondition::visibilityOfElementLocated(WebDriverBy::cssSelector('.foo')); @@ -208,6 +190,88 @@ public function testShouldDetectTextToBePresentInElementCondition() $this->assertTrue($this->wait->until($condition)); } + public function testShouldDetectElementTextIsCondition() + { + // Set-up the consecutive calls to apply() as follows: + // Call #1: throws NoSuchElementException + // Call #2: return Element, but getText will throw StaleElementReferenceException + // Call #3: return Element, getText will return not-matching text + // Call #4: return Element, getText will return new text and condition will match + + $element = $this->createRemoteWebElementMock(); + $element->expects($this->at(0)) + ->method('getText') + ->willThrowException(new StaleElementReferenceException('')); + + $element->expects($this->at(1)) + ->method('getText') + ->willReturn('this is a new text, but not exactly'); + + $element->expects($this->at(2)) + ->method('getText') + ->willReturn('this is a new text'); + + $this->setupDriverToReturnElementAfterAnException($element, 4); + + $condition = WebDriverExpectedCondition::elementTextIs( + WebDriverBy::cssSelector('.foo'), + 'this is a new text' + ); + + $this->assertTrue($this->wait->until($condition)); + } + + public function testShouldDetectElementTextMatchesCondition() + { + // Set-up the consecutive calls to apply() as follows: + // Call #1: throws NoSuchElementException + // Call #2: return Element, but getText will throw StaleElementReferenceException + // Call #3: return Element, getText will return not-matching text + // Call #4: return Element, getText will return matching text + + $element = $this->createRemoteWebElementMock(); + + $element->expects($this->at(0)) + ->method('getText') + ->willThrowException(new StaleElementReferenceException('')); + + $element->expects($this->at(1)) + ->method('getText') + ->willReturn('non-matching'); + + $element->expects($this->at(2)) + ->method('getText') + ->willReturn('matching-123'); + + $this->setupDriverToReturnElementAfterAnException($element, 4); + + $condition = WebDriverExpectedCondition::elementTextMatches( + WebDriverBy::cssSelector('.foo'), + '/matching-\d{3}/' + ); + + $this->assertTrue($this->wait->until($condition)); + } + + /** + * @param RemoteWebElement $element + * @param int $expectedNumberOfFindElementCalls + */ + private function setupDriverToReturnElementAfterAnException($element, $expectedNumberOfFindElementCalls) + { + $this->driverMock->expects($this->at(0)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willThrowException(new NoSuchElementException('')); + + for ($i = 1; $i < $expectedNumberOfFindElementCalls; $i++) { + $this->driverMock->expects($this->at($i)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + } + } + /** * @todo Replace with createMock() once PHP 5.5 support is dropped * @return \PHPUnit_Framework_MockObject_MockObject|RemoteWebElement From 3b686905b8dd9c5b36b49dd4f4301f831fb1f4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 17 Dec 2016 17:54:57 +0100 Subject: [PATCH 084/600] Deprecate textToBePresentInElement condition in favor of elementTextContains --- lib/WebDriverExpectedCondition.php | 17 ++++++++++++++++- tests/unit/WebDriverExpectedConditionTest.php | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index f2e75d1a2..0ab230a6a 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -167,11 +167,26 @@ function () use ($element) { * An expectation for checking if the given text is present in the specified element. * To check exact text match use elementTextIs() condition. * + * @codeCoverageIgnore + * @deprecated Use WebDriverExpectedCondition::elementTextContains() instead * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. * @return bool WebDriverExpectedCondition Whether the text is present. */ public static function textToBePresentInElement(WebDriverBy $by, $text) + { + return self::elementTextContains($by, $text); + } + + /** + * An expectation for checking if the given text is present in the specified element. + * To check exact text match use elementTextIs() condition. + * + * @param WebDriverBy $by The locator used to find the element. + * @param string $text The text to be presented in the element. + * @return bool WebDriverExpectedCondition Whether the text is present. + */ + public static function elementTextContains(WebDriverBy $by, $text) { return new static( function (WebDriver $driver) use ($by, $text) { @@ -188,7 +203,7 @@ function (WebDriver $driver) use ($by, $text) { /** * An expectation for checking if the given text exactly equals the text in specified element. - * To check only partial substring of the text use textToBePresentInElement() condition. + * To check only partial substring of the text use elementTextContains() condition. * * @param WebDriverBy $by The locator used to find the element. * @param string $text The expected text of the element. diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index fda958486..a221b8012 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -162,7 +162,7 @@ public function testShouldDetectVisibilityOfCondition() $this->assertSame($element, $this->wait->until($condition)); } - public function testShouldDetectTextToBePresentInElementCondition() + public function testShouldDetectElementTextContainsCondition() { // Set-up the consecutive calls to apply() as follows: // Call #1: throws NoSuchElementException @@ -185,7 +185,7 @@ public function testShouldDetectTextToBePresentInElementCondition() $this->setupDriverToReturnElementAfterAnException($element, 4); - $condition = WebDriverExpectedCondition::textToBePresentInElement(WebDriverBy::cssSelector('.foo'), 'new'); + $condition = WebDriverExpectedCondition::elementTextContains(WebDriverBy::cssSelector('.foo'), 'new'); $this->assertTrue($this->wait->until($condition)); } From b6a59dd7f3cb5fc8bca1d2787f8a34c740f752dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 17 Dec 2016 17:18:25 +0100 Subject: [PATCH 085/600] Add new numberOfWindowsToBe condition to check number of opened window handles --- lib/WebDriverExpectedCondition.php | 15 +++++++++++++++ tests/unit/WebDriverExpectedConditionTest.php | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 0ab230a6a..6be57f834 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -474,6 +474,21 @@ function (WebDriver $driver) { ); } + /** + * An expectation checking the number of opened windows. + * + * @param int $expectedNumberOfWindows + * @return WebDriverExpectedCondition + */ + public static function numberOfWindowsToBe($expectedNumberOfWindows) + { + return new static( + function (WebDriver $driver) use ($expectedNumberOfWindows) { + return count($driver->getWindowHandles()) == $expectedNumberOfWindows; + } + ); + } + /** * An expectation with the logical opposite condition of the given condition. * diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index a221b8012..fea46f58f 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -253,6 +253,19 @@ public function testShouldDetectElementTextMatchesCondition() $this->assertTrue($this->wait->until($condition)); } + public function testShouldDetectNumberOfWindowsToBeCondition() + { + $this->driverMock->expects($this->any()) + ->method('getWindowHandles') + ->willReturnOnConsecutiveCalls(['one'], ['one', 'two', 'three'], ['one', 'two']); + + $condition = WebDriverExpectedCondition::numberOfWindowsToBe(2); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + /** * @param RemoteWebElement $element * @param int $expectedNumberOfFindElementCalls From 81ee780856500ff4df90f38cdf594f5bef9ab707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 01:53:02 +0100 Subject: [PATCH 086/600] Improve functional test stability on slower environments --- tests/functional/RemoteWebDriverTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 1ce4c9570..27cc57e17 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -98,6 +98,10 @@ public function testShouldGetWindowHandles() // Open second window $this->driver->findElement(WebDriverBy::cssSelector('a'))->click(); + $this->driver->wait()->until( + WebDriverExpectedCondition::numberOfWindowsToBe(2) + ); + $this->assertCount(2, $this->driver->getWindowHandles()); } From 17437fa0e61ed9c67736732075e8f47baba3d3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 02:29:03 +0100 Subject: [PATCH 087/600] Properly specify covered parts of RemoteWebDriver --- tests/functional/RemoteWebDriverTest.php | 42 +++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 27cc57e17..918b3514b 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -20,10 +20,13 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @covers Facebook\WebDriver\Remote\RemoteWebDriver + * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebDriver */ class RemoteWebDriverTest extends WebDriverTestCase { + /** + * @covers ::getTitle + */ public function testShouldGetPageTitle() { $this->driver->get($this->getTestPath('index.html')); @@ -34,6 +37,10 @@ public function testShouldGetPageTitle() ); } + /** + * @covers ::getCurrentURL + * @covers ::get + */ public function testShouldGetCurrentUrl() { $this->driver->get($this->getTestPath('index.html')); @@ -44,6 +51,9 @@ public function testShouldGetCurrentUrl() ); } + /** + * @covers ::getPageSource + */ public function testShouldGetPageSource() { $this->driver->get($this->getTestPath('index.html')); @@ -53,6 +63,9 @@ public function testShouldGetPageSource() $this->assertContains('Welcome to the facebook/php-webdriver testing page.', $source); } + /** + * @covers ::getSessionID + */ public function testShouldGetSessionId() { $sessionId = $this->driver->getSessionID(); @@ -61,6 +74,9 @@ public function testShouldGetSessionId() $this->assertNotEmpty($sessionId); } + /** + * @covers ::getAllSessions + */ public function testShouldGetAllSessions() { $sessions = RemoteWebDriver::getAllSessions(); @@ -73,6 +89,11 @@ public function testShouldGetAllSessions() $this->assertArrayHasKey('class', $sessions[0]); } + /** + * @covers ::getAllSessions + * @covers ::getCommandExecutor + * @covers ::quit + */ public function testShouldQuitAndUnsetExecutor() { $this->assertCount(1, RemoteWebDriver::getAllSessions()); @@ -84,6 +105,10 @@ public function testShouldQuitAndUnsetExecutor() $this->assertNull($this->driver->getCommandExecutor()); } + /** + * @covers ::getWindowHandle + * @covers ::getWindowHandles + */ public function testShouldGetWindowHandles() { $this->driver->get($this->getTestPath('open_new_window.html')); @@ -105,6 +130,9 @@ public function testShouldGetWindowHandles() $this->assertCount(2, $this->driver->getWindowHandles()); } + /** + * @covers ::getWindowHandles + */ public function testShouldCloseWindow() { $this->driver->get($this->getTestPath('open_new_window.html')); @@ -117,6 +145,9 @@ public function testShouldCloseWindow() $this->assertCount(1, $this->driver->getWindowHandles()); } + /** + * @covers ::executeScript + */ public function testShouldExecuteScriptAndDoNotBlockExecution() { $this->driver->get($this->getTestPath('index.html')); @@ -138,6 +169,9 @@ function(){document.getElementById("id_test").innerHTML = "Text changed by scrip $this->assertSame('Text changed by script', $element->getText()); } + /** + * @covers ::executeAsyncScript + */ public function testShouldExecuteAsyncScriptAndWaitUntilItIsFinished() { $this->driver->manage()->timeouts()->setScriptTimeout(1); @@ -163,6 +197,9 @@ function(){ $this->assertSame('Text changed by script', $element->getText()); } + /** + * @covers ::takeScreenshot + */ public function testShouldTakeScreenshot() { if (!extension_loaded('gd')) { @@ -183,6 +220,9 @@ public function testShouldTakeScreenshot() $this->assertGreaterThan(0, imagesy($image)); } + /** + * @covers ::takeScreenshot + */ public function testShouldSaveScreenshotToFile() { if (!extension_loaded('gd')) { From aa90f690c9b59a3a7f66551b201c2d916e00c802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 02:41:28 +0100 Subject: [PATCH 088/600] Update changelog --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d9f1f42..f4ed9fd1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,21 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added +- Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. +- Added option to pass required capabilities when creating `RemoteWebDriver`. (So far only desired capabilities were supported.) +- Added new expected conditions: + - `titleMatches` - current page title matches regular expression + - `elementTextIs` - text in element exactly equals given text + - `elementTextMatches` - text in element matches regular expression + - `elementTextContains` (as an alias for `textToBePresentInElement`) - text in element contains given text + - `numberOfWindowsToBe` - number of opened windows equals given number + +### Changed - `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve portability. - Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class. - Deprecated `setSessionID()` and `setCommandExecutor()` methods of `RemoteWebDriver` class; these values should be immutable and thus passed only via constructor. -- Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. -- Added option to pass required capabilities when creating `RemoteWebDriver`. (So far only desired capabilities were supported.) +- Deprecated `WebDriverExpectedCondition::textToBePresentInElement()` in favor of `elementTextContains()` ## 1.2.0 - 2016-10-14 - Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported). From 8e1d0c517a844241b35ec9f15c3e7b4f78a37600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mar=C3=ADn?= Date: Thu, 15 Dec 2016 11:11:09 +0100 Subject: [PATCH 089/600] Adding URL related conditions --- lib/WebDriverExpectedCondition.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 6be57f834..e203c552e 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -92,6 +92,36 @@ function (WebDriver $driver) use ($titleRegexp) { ); } + /** + * An expectation for checking the URL of a page. + * + * @param string $url The expected URL, which must be an exact match. + * @return bool WebDriverExpectedCondition True when the URL matches, false otherwise. + */ + public static function urlIs($url) + { + return new static( + function (WebDriver $driver) use ($url) { + return $url === $driver->getCurrentURL(); + } + ); + } + + /** + * An expectation for checking substring of the URL of a page. + * + * @param string $url The expected substring of the URL + * @return bool WebDriverExpectedCondition True when in URL, false otherwise. + */ + public static function urlContains($url) + { + return new static( + function (WebDriver $driver) use ($url) { + return strpos($driver->getCurrentURL(), $url) !== false; + } + ); + } + /** * An expectation for checking that an element is present on the DOM of a page. * This does not necessarily mean that the element is visible. From 8f9c3316dc16d9e78cec7ac97484e7c2dd9ba95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 13:15:07 +0100 Subject: [PATCH 090/600] Add urlMatches condition to test against regexp --- CHANGELOG.md | 5 ++- lib/WebDriverExpectedCondition.php | 15 +++++++ tests/unit/WebDriverExpectedConditionTest.php | 39 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4ed9fd1f..f49ce0aeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,13 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. - Added option to pass required capabilities when creating `RemoteWebDriver`. (So far only desired capabilities were supported.) - Added new expected conditions: + - `urlIs` - current URL exactly equals given value + - `urlContains` - current URL contains given text + - `urlMatches` - current URL matches regular expression - `titleMatches` - current page title matches regular expression - `elementTextIs` - text in element exactly equals given text - - `elementTextMatches` - text in element matches regular expression - `elementTextContains` (as an alias for `textToBePresentInElement`) - text in element contains given text + - `elementTextMatches` - text in element matches regular expression - `numberOfWindowsToBe` - number of opened windows equals given number ### Changed diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index e203c552e..0c70026f2 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -122,6 +122,21 @@ function (WebDriver $driver) use ($url) { ); } + /** + * An expectation for checking current page URL matches the given regular expression. + * + * @param string $urlRegexp The regular expression to test against. + * @return bool WebDriverExpectedCondition True when in url, false otherwise. + */ + public static function urlMatches($urlRegexp) + { + return new static( + function (WebDriver $driver) use ($urlRegexp) { + return (bool) preg_match($urlRegexp, $driver->getCurrentURL()); + } + ); + } + /** * An expectation for checking that an element is present on the DOM of a page. * This does not necessarily mean that the element is visible. diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index fea46f58f..93d98b392 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -80,6 +80,45 @@ public function testShouldDetectTitleMatchesCondition() $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); } + public function testShouldDetectUrlIsCondition() + { + $this->driverMock->expects($this->any()) + ->method('getCurrentURL') + ->willReturnOnConsecutiveCalls('https://old/', 'https://oldwithnew/', 'https://new/'); + + $condition = WebDriverExpectedCondition::urlIs('https://new/'); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + + public function testShouldDetectUrlContainsCondition() + { + $this->driverMock->expects($this->any()) + ->method('getCurrentURL') + ->willReturnOnConsecutiveCalls('https://old/', 'https://oldwithnew/', 'https://new/'); + + $condition = WebDriverExpectedCondition::urlContains('new'); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + + public function testShouldDetectUrlMatchesCondition() + { + $this->driverMock->expects($this->any()) + ->method('getCurrentURL') + ->willReturnOnConsecutiveCalls('https://non/matching/', 'https://matching/not/', 'https://matching/123/'); + + $condition = WebDriverExpectedCondition::urlMatches('/matching\/\d{3}\/$/'); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + public function testShouldDetectPresenceOfElementLocatedCondition() { $element = new RemoteWebElement(new RemoteExecuteMethod($this->driverMock), 'id'); From f2dc151ceeb99dce48ff6db741c7edb0cce7fb9f Mon Sep 17 00:00:00 2001 From: Cristian Fedatov Date: Wed, 21 Dec 2016 15:13:24 +0200 Subject: [PATCH 091/600] Possibility to select option by partial text using selectByVisiblePartialText method. (fixes #375) --- CHANGELOG.md | 1 + lib/WebDriverSelect.php | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f49ce0aeb..fdd5a9019 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - `elementTextContains` (as an alias for `textToBePresentInElement`) - text in element contains given text - `elementTextMatches` - text in element matches regular expression - `numberOfWindowsToBe` - number of opened windows equals given number +- Possibility to select option of `' => ['#select'], + ' + +
+ + +
+ + + +
+ + + +
+ +

+ +

+ + + + + From 790ac29e93eeee2dab40b92ffb0a852ff4195c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 19:41:58 +0100 Subject: [PATCH 094/600] Allow to deselect option of ` by its partial text (using `selectByVisiblePartialText()`) +- `XPathEscaper` helper class to quote XPaths containing both single and double quotes. ### Changed - `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve portability. @@ -23,6 +24,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Deprecated `WebDriverExpectedCondition::textToBePresentInElement()` in favor of `elementTextContains()` - Throw an exception when attempting to deselect options of non-multiselect (it already didn't have any effect, but was silently ignored). +### Fixed +- XPath escaping in `select*()` and `deselect*()` methods of `WebDriverSelect`. + ## 1.2.0 - 2016-10-14 - Added initial support of remote Microsoft Edge browser (but starting local EdgeDriver is still not supported). - Utilize late static binding to make eg. `WebDriverBy` and `DesiredCapabilities` classes easily extensible. diff --git a/lib/Support/XPathEscaper.php b/lib/Support/XPathEscaper.php new file mode 100644 index 000000000..10271128c --- /dev/null +++ b/lib/Support/XPathEscaper.php @@ -0,0 +1,45 @@ + concat('foo', "'" ,'"bar') + * + * @param string $xpathToEscape The xpath to be converted. + * @return string The escaped string. + */ + public static function escapeQuotes($xpathToEscape) + { + // Single quotes not present => we can quote in them + if (strpos($xpathToEscape, "'") === false) { + return sprintf("'%s'", $xpathToEscape); + } + + // Double quotes not present => we can quote in them + if (strpos($xpathToEscape, '"') === false) { + return sprintf('"%s"', $xpathToEscape); + } + + // Both single and double quotes are present + return sprintf( + "concat('%s')", + str_replace("'", "', \"'\" ,'", $xpathToEscape) + ); + } +} diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index e45bcc22d..a55a0ff90 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -18,6 +18,7 @@ use Facebook\WebDriver\Exception\NoSuchElementException; use Facebook\WebDriver\Exception\UnexpectedTagNameException; use Facebook\WebDriver\Exception\UnsupportedOperationException; +use Facebook\WebDriver\Support\XPathEscaper; /** * Models a SELECT tag, providing helper methods to select and deselect options. @@ -128,7 +129,7 @@ public function selectByIndex($index) public function selectByValue($value) { $matched = false; - $xpath = './/option[@value = ' . $this->escapeQuotes($value) . ']'; + $xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { @@ -161,7 +162,7 @@ public function selectByValue($value) public function selectByVisibleText($text) { $matched = false; - $xpath = './/option[normalize-space(.) = ' . $this->escapeQuotes($text) . ']'; + $xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { @@ -210,7 +211,7 @@ public function selectByVisibleText($text) public function selectByVisiblePartialText($text) { $matched = false; - $xpath = './/option[contains(normalize-space(.), ' . $this->escapeQuotes($text) . ')]'; + $xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { @@ -282,7 +283,7 @@ public function deselectByValue($value) throw new UnsupportedOperationException('You may only deselect options of a multi-select'); } - $xpath = './/option[@value = ' . $this->escapeQuotes($value) . ']'; + $xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { if ($option->isSelected()) { @@ -306,7 +307,7 @@ public function deselectByVisibleText($text) throw new UnsupportedOperationException('You may only deselect options of a multi-select'); } - $xpath = './/option[normalize-space(.) = ' . $this->escapeQuotes($text) . ']'; + $xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { if ($option->isSelected()) { @@ -330,7 +331,7 @@ public function deselectByVisiblePartialText($text) throw new UnsupportedOperationException('You may only deselect options of a multi-select'); } - $xpath = './/option[contains(normalize-space(.), ' . $this->escapeQuotes($text) . ')]'; + $xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { if ($option->isSelected()) { @@ -338,36 +339,4 @@ public function deselectByVisiblePartialText($text) } } } - - /** - * Convert strings with both quotes and ticks into: - * foo'"bar -> concat("foo'", '"', "bar") - * - * @param string $to_escape The string to be converted. - * @return string The escaped string. - */ - protected function escapeQuotes($to_escape) - { - if (strpos($to_escape, '"') !== false && strpos($to_escape, "'") !== false) { - $substrings = explode('"', $to_escape); - - $escaped = 'concat('; - $first = true; - foreach ($substrings as $string) { - if (!$first) { - $escaped .= ", '\"',"; - $first = false; - } - $escaped .= '"' . $string . '"'; - } - - return $escaped; - } - - if (strpos($to_escape, '"') !== false) { - return sprintf("'%s'", $to_escape); - } - - return sprintf('"%s"', $to_escape); - } } diff --git a/tests/unit/Support/XPathEscaperTest.php b/tests/unit/Support/XPathEscaperTest.php new file mode 100644 index 000000000..21ac4aea0 --- /dev/null +++ b/tests/unit/Support/XPathEscaperTest.php @@ -0,0 +1,49 @@ +assertSame($expectedOutput, $output); + } + + /** + * @return array[] + */ + public function xpathProvider() + { + return [ + 'empty string encapsulate in single quotes' => ['', "''"], + 'string without quotes encapsulate in single quotes' => ['foo bar', "'foo bar'"], + 'string with single quotes encapsulate in double quotes' => ['foo\'bar\'', '"foo\'bar\'"'], + 'string with double quotes encapsulate in single quotes' => ['foo"bar"', '\'foo"bar"\''], + 'string with both types of quotes concatenate' => ['\'"', "concat('', \"'\" ,'\"')"], + 'string with multiple both types of quotes concatenate' => [ + 'a \'b\'"c"', + "concat('a ', \"'\" ,'b', \"'\" ,'\"c\"')", + ], + ]; + } +} From c9d58a84a28e01713c183c9c4d5a855154bc70e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 21:00:25 +0100 Subject: [PATCH 097/600] No need to check for multiple values when selecting/deselecting by index, as the index is unique --- lib/WebDriverSelect.php | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index a55a0ff90..b071291ae 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -97,23 +97,17 @@ public function getFirstSelectedOption() */ public function selectByIndex($index) { - $matched = false; foreach ($this->getOptions() as $option) { if ($option->getAttribute('index') === (string) $index) { if (!$option->isSelected()) { $option->click(); - if (!$this->isMultiple()) { - return; - } } - $matched = true; + + return; } } - if (!$matched) { - throw new NoSuchElementException( - sprintf('Cannot locate option with index: %d', $index) - ); - } + + throw new NoSuchElementException(sprintf('Cannot locate option with index: %d', $index)); } /** @@ -262,8 +256,12 @@ public function deselectByIndex($index) } foreach ($this->getOptions() as $option) { - if ($option->getAttribute('index') === (string) $index && $option->isSelected()) { - $option->click(); + if ($option->getAttribute('index') === (string) $index) { + if ($option->isSelected()) { + $option->click(); + } + + return; } } } From 6e91c998c4b1c4a4bfeac4385da7b65b188f156e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 21:04:29 +0100 Subject: [PATCH 098/600] DRY when (de)selecting options --- lib/WebDriverSelect.php | 62 +++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index b071291ae..e8e9587ed 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -99,9 +99,7 @@ public function selectByIndex($index) { foreach ($this->getOptions() as $option) { if ($option->getAttribute('index') === (string) $index) { - if (!$option->isSelected()) { - $option->click(); - } + $this->selectOption($option); return; } @@ -127,9 +125,7 @@ public function selectByValue($value) $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { - if (!$option->isSelected()) { - $option->click(); - } + $this->selectOption($option); if (!$this->isMultiple()) { return; } @@ -160,9 +156,7 @@ public function selectByVisibleText($text) $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { - if (!$option->isSelected()) { - $option->click(); - } + $this->selectOption($option); if (!$this->isMultiple()) { return; } @@ -174,9 +168,7 @@ public function selectByVisibleText($text) if (!$matched) { foreach ($this->getOptions() as $option) { if ($option->getText() === $text) { - if (!$option->isSelected()) { - $option->click(); - } + $this->selectOption($option); if (!$this->isMultiple()) { return; } @@ -209,9 +201,7 @@ public function selectByVisiblePartialText($text) $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { - if (!$option->isSelected()) { - $option->click(); - } + $this->selectOption($option); if (!$this->isMultiple()) { return; } @@ -237,9 +227,7 @@ public function deselectAll() } foreach ($this->getOptions() as $option) { - if ($option->isSelected()) { - $option->click(); - } + $this->deselectOption($option); } } @@ -257,9 +245,7 @@ public function deselectByIndex($index) foreach ($this->getOptions() as $option) { if ($option->getAttribute('index') === (string) $index) { - if ($option->isSelected()) { - $option->click(); - } + $this->deselectOption($option); return; } @@ -284,9 +270,7 @@ public function deselectByValue($value) $xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { - if ($option->isSelected()) { - $option->click(); - } + $this->deselectOption($option); } } @@ -308,9 +292,7 @@ public function deselectByVisibleText($text) $xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { - if ($option->isSelected()) { - $option->click(); - } + $this->deselectOption($option); } } @@ -332,9 +314,29 @@ public function deselectByVisiblePartialText($text) $xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]'; $options = $this->element->findElements(WebDriverBy::xpath($xpath)); foreach ($options as $option) { - if ($option->isSelected()) { - $option->click(); - } + $this->deselectOption($option); + } + } + + /** + * Mark option selected + * @param WebDriverElement $option + */ + protected function selectOption(WebDriverElement $option) + { + if (!$option->isSelected()) { + $option->click(); + } + } + + /** + * Mark option not selected + * @param WebDriverElement $option + */ + protected function deselectOption(WebDriverElement $option) + { + if ($option->isSelected()) { + $option->click(); } } } From fa04797db3e48cab6be9265f85c6efec1a3ade9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 8 Jan 2017 21:11:26 +0100 Subject: [PATCH 099/600] Extract WebDriverSelectInterface, to allow implementation of custom select-like components Eg. components not built around and actual select tag. --- CHANGELOG.md | 1 + lib/WebDriverSelect.php | 96 +---------------------- lib/WebDriverSelectInterface.php | 127 +++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 92 deletions(-) create mode 100644 lib/WebDriverSelectInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index caf23c691..12c55520e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - `numberOfWindowsToBe` - number of opened windows equals given number - Possibility to select option of ` tag, providing helper methods to select and deselect options. */ -class WebDriverSelect +class WebDriverSelect implements WebDriverSelectInterface { + /** @var WebDriverElement */ private $element; + /** @var bool */ private $isMulti; public function __construct(WebDriverElement $element) @@ -40,25 +42,16 @@ public function __construct(WebDriverElement $element) $this->isMulti = ($value === 'true'); } - /** - * @return bool Whether this select element support selecting multiple options. - */ public function isMultiple() { return $this->isMulti; } - /** - * @return WebDriverElement[] All options belonging to this select tag. - */ public function getOptions() { return $this->element->findElements(WebDriverBy::tagName('option')); } - /** - * @return WebDriverElement[] All selected options belonging to this select tag. - */ public function getAllSelectedOptions() { $selected_options = []; @@ -71,12 +64,6 @@ public function getAllSelectedOptions() return $selected_options; } - /** - * @throws NoSuchElementException - * - * @return WebDriverElement The first selected option in this select tag (or - * the currently selected option in a normal select) - */ public function getFirstSelectedOption() { foreach ($this->getOptions() as $option) { @@ -88,13 +75,6 @@ public function getFirstSelectedOption() throw new NoSuchElementException('No options are selected'); } - /** - * Select the option at the given index. - * - * @param int $index The index of the option. (0-based) - * - * @throws NoSuchElementException - */ public function selectByIndex($index) { foreach ($this->getOptions() as $option) { @@ -108,16 +88,6 @@ public function selectByIndex($index) throw new NoSuchElementException(sprintf('Cannot locate option with index: %d', $index)); } - /** - * Select all options that have value attribute matching the argument. That - * is, when given "foo" this would select an option like: - * - * ; - * - * @param string $value The value to match against. - * - * @throws NoSuchElementException - */ public function selectByValue($value) { $matched = false; @@ -139,16 +109,6 @@ public function selectByValue($value) } } - /** - * Select all options that display text matching the argument. That is, when - * given "Bar" this would select an option like: - * - * ; - * - * @param string $text The visible text to match against. - * - * @throws NoSuchElementException - */ public function selectByVisibleText($text) { $matched = false; @@ -184,16 +144,6 @@ public function selectByVisibleText($text) } } - /** - * Select all options that display text partially matching the argument. That is, when - * given "Bar" this would select an option like: - * - * ; - * - * @param string $text The visible text to match against. - * - * @throws NoSuchElementException - */ public function selectByVisiblePartialText($text) { $matched = false; @@ -215,11 +165,6 @@ public function selectByVisiblePartialText($text) } } - /** - * Deselect all options in multiple select tag. - * - * @throws UnsupportedOperationException If the SELECT does not support multiple selections - */ public function deselectAll() { if (!$this->isMultiple()) { @@ -231,12 +176,6 @@ public function deselectAll() } } - /** - * Deselect the option at the given index. - * - * @param int $index The index of the option. (0-based) - * @throws UnsupportedOperationException If the SELECT does not support multiple selections - */ public function deselectByIndex($index) { if (!$this->isMultiple()) { @@ -252,15 +191,6 @@ public function deselectByIndex($index) } } - /** - * Deselect all options that have value attribute matching the argument. That - * is, when given "foo" this would deselect an option like: - * - * ; - * - * @param string $value The value to match against. - * @throws UnsupportedOperationException If the SELECT does not support multiple selections - */ public function deselectByValue($value) { if (!$this->isMultiple()) { @@ -274,15 +204,6 @@ public function deselectByValue($value) } } - /** - * Deselect all options that display text matching the argument. That is, when - * given "Bar" this would deselect an option like: - * - * ; - * - * @param string $text The visible text to match against. - * @throws UnsupportedOperationException If the SELECT does not support multiple selections - */ public function deselectByVisibleText($text) { if (!$this->isMultiple()) { @@ -296,15 +217,6 @@ public function deselectByVisibleText($text) } } - /** - * Deselect all options that display text matching the argument. That is, when - * given "Bar" this would deselect an option like: - * - * ; - * - * @param string $text The visible text to match against. - * @throws UnsupportedOperationException If the SELECT does not support multiple selections - */ public function deselectByVisiblePartialText($text) { if (!$this->isMultiple()) { diff --git a/lib/WebDriverSelectInterface.php b/lib/WebDriverSelectInterface.php new file mode 100644 index 000000000..cec06a33f --- /dev/null +++ b/lib/WebDriverSelectInterface.php @@ -0,0 +1,127 @@ +Bar; + * + * @param string $value The value to match against. + * + * @throws NoSuchElementException + */ + public function selectByValue($value); + + /** + * Select all options that display text matching the argument. That is, when given "Bar" this would + * select an option like: + * + * ; + * + * @param string $text The visible text to match against. + * + * @throws NoSuchElementException + */ + public function selectByVisibleText($text); + + /** + * Select all options that display text partially matching the argument. That is, when given "Bar" this would + * select an option like: + * + * ; + * + * @param string $text The visible text to match against. + * + * @throws NoSuchElementException + */ + public function selectByVisiblePartialText($text); + + /** + * Deselect all options in multiple select tag. + * + * @throws UnsupportedOperationException If the SELECT does not support multiple selections + */ + public function deselectAll(); + + /** + * Deselect the option at the given index. + * + * @param int $index The index of the option. (0-based) + * @throws UnsupportedOperationException If the SELECT does not support multiple selections + */ + public function deselectByIndex($index); + + /** + * Deselect all options that have value attribute matching the argument. That is, when given "foo" this would + * deselect an option like: + * + * ; + * + * @param string $value The value to match against. + * @throws UnsupportedOperationException If the SELECT does not support multiple selections + */ + public function deselectByValue($value); + + /** + * Deselect all options that display text matching the argument. That is, when given "Bar" this would + * deselect an option like: + * + * ; + * + * @param string $text The visible text to match against. + * @throws UnsupportedOperationException If the SELECT does not support multiple selections + */ + public function deselectByVisibleText($text); + + /** + * Deselect all options that display text matching the argument. That is, when given "Bar" this would + * deselect an option like: + * + * ; + * + * @param string $text The visible text to match against. + * @throws UnsupportedOperationException If the SELECT does not support multiple selections + */ + public function deselectByVisiblePartialText($text); +} From 0979f5587a8e17d014c4e69d9415de32e3ff65a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 10 Jan 2017 14:57:43 +0100 Subject: [PATCH 100/600] Add some more tests for RemoteWebElement --- tests/functional/RemoteWebElementTest.php | 58 +++++++++++++++++++++-- tests/functional/web/index.html | 12 +++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index e176d4189..1a04cf1a8 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -23,11 +23,59 @@ class RemoteWebElementTest extends WebDriverTestCase public function testShouldGetText() { $this->driver->get($this->getTestPath('index.html')); - $element = $this->driver->findElement(WebDriverBy::id('welcome')); + $elementWithSimpleText = $this->driver->findElement(WebDriverBy::id('text-simple')); + $elementWithTextWithSpaces = $this->driver->findElement(WebDriverBy::id('text-with-spaces')); - $this->assertEquals( - 'Welcome to the facebook/php-webdriver testing page.', - $element->getText() - ); + $this->assertEquals('Foo bar text', $elementWithSimpleText->getText()); + $this->assertEquals('Multiple spaces are stripped', $elementWithTextWithSpaces->getText()); + } + + public function testShouldGetAttributeValue() + { + $this->driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement(WebDriverBy::id('text-simple')); + + $this->assertSame('note', $element->getAttribute('role')); + $this->assertSame('height: 5em; border: 1px solid black;', $element->getAttribute('style')); + $this->assertSame('text-simple', $element->getAttribute('id')); + } + + public function testShouldGetLocation() + { + $this->driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement(WebDriverBy::id('element-with-location')); + + $elementLocation = $element->getLocation(); + $this->assertInstanceOf(WebDriverPoint::class, $elementLocation); + $this->assertSame(33, $elementLocation->getX()); + $this->assertSame(500, $elementLocation->getY()); + } + + public function testShouldGetSize() + { + $this->driver->get($this->getTestPath('index.html')); + + $element = $this->driver->findElement(WebDriverBy::id('element-with-location')); + + $elementSize = $element->getSize(); + $this->assertInstanceOf(WebDriverDimension::class, $elementSize); + $this->assertSame(333, $elementSize->getWidth()); + $this->assertSame(66, $elementSize->getHeight()); + } + + public function testShouldGetCssValue() + { + $this->driver->get($this->getTestPath('index.html')); + + $elementWithBorder = $this->driver->findElement(WebDriverBy::id('text-simple')); + $elementWithoutBorder = $this->driver->findElement(WebDriverBy::id('text-with-spaces')); + + $this->assertSame('solid', $elementWithBorder->getCSSValue('border-left-style')); + $this->assertSame('none', $elementWithoutBorder->getCSSValue('border-left-style')); + + $this->assertSame('rgba(0, 0, 0, 1)', $elementWithBorder->getCSSValue('border-left-color')); + $this->assertSame('rgba(0, 0, 0, 1)', $elementWithoutBorder->getCSSValue('border-left-color')); } } diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index 139a25865..282706cce 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -16,5 +16,17 @@

Welcome to the facebook/php-webdriver testing page.

  • Second
  • Third
  • + +

    Foo bar text

    +

    + Multiple spaces are + stripped +

    + +
    + Foo +
    + + From efe3dc68124ba299d2b84263f91b6dd44d586327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 10 Jan 2017 14:06:06 +0100 Subject: [PATCH 101/600] Optimize getAllSelectedOptions method for single select, because it always contains exactly one selected option --- CHANGELOG.md | 1 + lib/WebDriverSelect.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12c55520e..112936c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Deprecated `setSessionID()` and `setCommandExecutor()` methods of `RemoteWebDriver` class; these values should be immutable and thus passed only via constructor. - Deprecated `WebDriverExpectedCondition::textToBePresentInElement()` in favor of `elementTextContains()` - Throw an exception when attempting to deselect options of non-multiselect (it already didn't have any effect, but was silently ignored). +- Optimize performance of `(de)selectByIndex()` and `getAllSelectedOptions()` methods of `WebDriverSelect` when used with non-multiple select element. ### Fixed - XPath escaping in `select*()` and `deselect*()` methods of `WebDriverSelect`. diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index 7e7455ae5..dc6a84038 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -58,6 +58,10 @@ public function getAllSelectedOptions() foreach ($this->getOptions() as $option) { if ($option->isSelected()) { $selected_options[] = $option; + + if (!$this->isMultiple()) { + return $selected_options; + } } } From 3df0ef7e929e984f2747b0a2846bc91b5a9f1d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 11 Jan 2017 23:57:07 +0100 Subject: [PATCH 102/600] Various codestyle and typehint fixes --- lib/Chrome/ChromeDriver.php | 3 +- lib/Firefox/FirefoxProfile.php | 5 +- lib/Interactions/WebDriverActions.php | 5 +- lib/Remote/RemoteWebDriver.php | 10 ++-- lib/Remote/Service/DriverService.php | 2 +- lib/Support/Events/EventFiringWebDriver.php | 27 +++++++-- lib/Support/Events/EventFiringWebElement.php | 27 +++++++-- lib/WebDriver.php | 7 +++ lib/WebDriverExpectedCondition.php | 56 ++++++++++--------- .../unit/Exception/WebDriverExceptionTest.php | 2 +- 10 files changed, 99 insertions(+), 45 deletions(-) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 7aac128e4..249c4f1b5 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -63,7 +63,8 @@ public static function create( $connection_timeout_in_ms = null, $request_timeout_in_ms = null, $http_proxy = null, - $http_proxy_port = null + $http_proxy_port = null, + DesiredCapabilities $required_capabilities = null ) { throw new WebDriverException('Please use ChromeDriver::start() instead.'); } diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 6dd4d41b3..00dcebd5c 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -226,9 +226,12 @@ private function installExtension($extension, $profile_dir) $ext_dir = $profile_dir . '/extensions/' . $matches[1]; mkdir($ext_dir, 0777, true); $this->extractTo($extension, $ext_dir); + } else { + $this->deleteDirectory($temp_dir); + + throw new WebDriverException('Cannot get the extension id from the install manifest.'); } - // clean up $this->deleteDirectory($temp_dir); return $ext_dir; diff --git a/lib/Interactions/WebDriverActions.php b/lib/Interactions/WebDriverActions.php index 281b84dac..e97796854 100644 --- a/lib/Interactions/WebDriverActions.php +++ b/lib/Interactions/WebDriverActions.php @@ -27,6 +27,7 @@ use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction; use Facebook\WebDriver\WebDriver; use Facebook\WebDriver\WebDriverElement; +use Facebook\WebDriver\WebDriverHasInputDevices; /** * WebDriver action builder. It implements the builder pattern. @@ -39,9 +40,9 @@ class WebDriverActions protected $action; /** - * @param WebDriver $driver + * @param WebDriverHasInputDevices $driver */ - public function __construct(WebDriver $driver) + public function __construct(WebDriverHasInputDevices $driver) { $this->driver = $driver; $this->keyboard = $driver->getKeyboard(); diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index dd1be325a..c2ecd8d37 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -20,16 +20,16 @@ use Facebook\WebDriver\WebDriver; use Facebook\WebDriver\WebDriverBy; use Facebook\WebDriver\WebDriverCapabilities; -use Facebook\WebDriver\WebDriverCommandExecutor; use Facebook\WebDriver\WebDriverElement; +use Facebook\WebDriver\WebDriverHasInputDevices; use Facebook\WebDriver\WebDriverNavigation; use Facebook\WebDriver\WebDriverOptions; use Facebook\WebDriver\WebDriverWait; -class RemoteWebDriver implements WebDriver, JavaScriptExecutor +class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInputDevices { /** - * @var HttpCommandExecutor + * @var HttpCommandExecutor|null */ protected $executor; /** @@ -507,10 +507,10 @@ protected function newElement($id) * @deprecated To be removed in the future. Executor should be passed in the constructor. * @internal * @codeCoverageIgnore - * @param WebDriverCommandExecutor $executor + * @param HttpCommandExecutor $executor * @return RemoteWebDriver */ - public function setCommandExecutor(WebDriverCommandExecutor $executor) + public function setCommandExecutor(HttpCommandExecutor $executor) { $this->executor = $executor; diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index 634c45864..c15ef94f9 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -46,7 +46,7 @@ class DriverService private $environment; /** - * @var Process + * @var Process|null */ private $process; diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index 268b35ac7..34514e9cd 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -50,8 +50,6 @@ public function __construct(WebDriver $driver, WebDriverDispatcher $dispatcher = $this->dispatcher->setDefaultDriver($this); } $this->driver = $driver; - - return $this; } /** @@ -105,6 +103,7 @@ public function get($url) $this->driver->get($url); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterNavigateTo', $url, $this); @@ -127,6 +126,7 @@ public function findElements(WebDriverBy $by) } } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterFindBy', $by, null, $this); @@ -147,6 +147,7 @@ public function findElement(WebDriverBy $by) $element = $this->newElement($this->driver->findElement($by)); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterFindBy', $by, null, $this); @@ -174,6 +175,7 @@ public function executeScript($script, array $arguments = []) $result = $this->driver->executeScript($script, $arguments); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterScript', $script, $this); @@ -200,6 +202,7 @@ public function executeAsyncScript($script, array $arguments = []) $result = $this->driver->executeAsyncScript($script, $arguments); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterScript', $script, $this); @@ -218,6 +221,7 @@ public function close() return $this; } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -231,6 +235,7 @@ public function getCurrentURL() return $this->driver->getCurrentURL(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -244,6 +249,7 @@ public function getPageSource() return $this->driver->getPageSource(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -257,6 +263,7 @@ public function getTitle() return $this->driver->getTitle(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -270,6 +277,7 @@ public function getWindowHandle() return $this->driver->getWindowHandle(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -283,6 +291,7 @@ public function getWindowHandles() return $this->driver->getWindowHandles(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -295,6 +304,7 @@ public function quit() $this->driver->quit(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -309,6 +319,7 @@ public function takeScreenshot($save_as = null) return $this->driver->takeScreenshot($save_as); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -324,6 +335,7 @@ public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) return $this->driver->wait($timeout_in_second, $interval_in_millisecond); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -337,6 +349,7 @@ public function manage() return $this->driver->manage(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -353,6 +366,7 @@ public function navigate() ); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -366,6 +380,7 @@ public function switchTo() return $this->driver->switchTo(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -379,13 +394,16 @@ public function getTouch() return $this->driver->getTouch(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } - private function dispatchOnException($exception) + /** + * @param WebDriverException $exception + */ + private function dispatchOnException(WebDriverException $exception) { $this->dispatch('onException', $exception, $this); - throw $exception; } public function execute($name, $params) @@ -394,6 +412,7 @@ public function execute($name, $params) return $this->driver->execute($name, $params); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } } diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index 872c59c5e..b9591b0ef 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -43,8 +43,6 @@ public function __construct(WebDriverElement $element, WebDriverDispatcher $disp { $this->element = $element; $this->dispatcher = $dispatcher; - - return $this; } /** @@ -97,6 +95,7 @@ public function sendKeys($value) $this->element->sendKeys($value); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterChangeValueOf', $this); @@ -114,6 +113,7 @@ public function click() $this->element->click(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch('afterClickOn', $this); @@ -138,6 +138,7 @@ public function findElement(WebDriverBy $by) $element = $this->newElement($this->element->findElement($by)); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch( @@ -170,6 +171,7 @@ public function findElements(WebDriverBy $by) } } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } $this->dispatch( 'afterFindBy', @@ -193,6 +195,7 @@ public function clear() return $this; } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -207,6 +210,7 @@ public function getAttribute($attribute_name) return $this->element->getAttribute($attribute_name); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -221,6 +225,7 @@ public function getCSSValue($css_property_name) return $this->element->getCSSValue($css_property_name); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -234,6 +239,7 @@ public function getLocation() return $this->element->getLocation(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -247,6 +253,7 @@ public function getLocationOnScreenOnceScrolledIntoView() return $this->element->getLocationOnScreenOnceScrolledIntoView(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -259,6 +266,7 @@ public function getCoordinates() return $this->element->getCoordinates(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -272,6 +280,7 @@ public function getSize() return $this->element->getSize(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -285,6 +294,7 @@ public function getTagName() return $this->element->getTagName(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -298,6 +308,7 @@ public function getText() return $this->element->getText(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -311,6 +322,7 @@ public function isDisplayed() return $this->element->isDisplayed(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -324,6 +336,7 @@ public function isEnabled() return $this->element->isEnabled(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -337,6 +350,7 @@ public function isSelected() return $this->element->isSelected(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -352,6 +366,7 @@ public function submit() return $this; } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -365,6 +380,7 @@ public function getID() return $this->element->getID(); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -380,16 +396,19 @@ public function equals(WebDriverElement $other) return $this->element->equals($other); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } - private function dispatchOnException($exception) + /** + * @param WebDriverException $exception + */ + private function dispatchOnException(WebDriverException $exception) { $this->dispatch( 'onException', $exception, $this->dispatcher->getDefaultDriver() ); - throw $exception; } } diff --git a/lib/WebDriver.php b/lib/WebDriver.php index 85e8c1931..48aeefa6b 100755 --- a/lib/WebDriver.php +++ b/lib/WebDriver.php @@ -15,6 +15,8 @@ namespace Facebook\WebDriver; +use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen; + /** * The interface for WebDriver. */ @@ -126,6 +128,11 @@ public function navigate(); */ public function switchTo(); + /** + * @return WebDriverTouchScreen + */ + public function getTouch(); + /** * @param string $name * @param array $params diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 0c70026f2..930a13733 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -51,7 +51,7 @@ protected function __construct(callable $apply) * An expectation for checking the title of a page. * * @param string $title The expected title, which must be an exact match. - * @return bool WebDriverExpectedCondition True when the title matches, false otherwise. + * @return WebDriverExpectedCondition Condition returns whether current page title equals given string. */ public static function titleIs($title) { @@ -66,7 +66,7 @@ function (WebDriver $driver) use ($title) { * An expectation for checking substring of a page Title. * * @param string $title The expected substring of Title. - * @return bool WebDriverExpectedCondition True when in title, false otherwise. + * @return WebDriverExpectedCondition Condition returns whether current page title contains given string. */ public static function titleContains($title) { @@ -81,7 +81,8 @@ function (WebDriver $driver) use ($title) { * An expectation for checking current page title matches the given regular expression. * * @param string $titleRegexp The regular expression to test against. - * @return bool WebDriverExpectedCondition True when in title, false otherwise. + * @return WebDriverExpectedCondition Condition returns whether current page title matches the regular + * expression. */ public static function titleMatches($titleRegexp) { @@ -96,7 +97,7 @@ function (WebDriver $driver) use ($titleRegexp) { * An expectation for checking the URL of a page. * * @param string $url The expected URL, which must be an exact match. - * @return bool WebDriverExpectedCondition True when the URL matches, false otherwise. + * @return WebDriverExpectedCondition Condition returns whether current URL equals given one. */ public static function urlIs($url) { @@ -111,7 +112,7 @@ function (WebDriver $driver) use ($url) { * An expectation for checking substring of the URL of a page. * * @param string $url The expected substring of the URL - * @return bool WebDriverExpectedCondition True when in URL, false otherwise. + * @return WebDriverExpectedCondition Condition returns whether current URL contains given string. */ public static function urlContains($url) { @@ -126,7 +127,7 @@ function (WebDriver $driver) use ($url) { * An expectation for checking current page URL matches the given regular expression. * * @param string $urlRegexp The regular expression to test against. - * @return bool WebDriverExpectedCondition True when in url, false otherwise. + * @return WebDriverExpectedCondition Condition returns whether current URL matches the regular expression. */ public static function urlMatches($urlRegexp) { @@ -142,7 +143,7 @@ function (WebDriver $driver) use ($urlRegexp) { * This does not necessarily mean that the element is visible. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition The element which is located. + * @return WebDriverExpectedCondition Condition returns the element which is located. */ public static function presenceOfElementLocated(WebDriverBy $by) { @@ -157,7 +158,7 @@ function (WebDriver $driver) use ($by) { * An expectation for checking that there is at least one element present on a web page. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition An array of WebDriverElements once they are located. + * @return WebDriverExpectedCondition Condition returns an array of WebDriverElements once they are located. */ public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) { @@ -175,7 +176,7 @@ function (WebDriver $driver) use ($by) { * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition The element which is located and visible. + * @return WebDriverExpectedCondition Condition returns the element which is located and visible. */ public static function visibilityOfElementLocated(WebDriverBy $by) { @@ -197,7 +198,8 @@ function (WebDriver $driver) use ($by) { * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverElement $element The element to be checked. - * @return WebDriverExpectedCondition The same WebDriverElement once it is visible. + * @return WebDriverExpectedCondition Condition returns the same WebDriverElement once it is + * visible. */ public static function visibilityOf(WebDriverElement $element) { @@ -216,7 +218,7 @@ function () use ($element) { * @deprecated Use WebDriverExpectedCondition::elementTextContains() instead * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. - * @return bool WebDriverExpectedCondition Whether the text is present. + * @return WebDriverExpectedCondition Condition returns whether the text is present in the element. */ public static function textToBePresentInElement(WebDriverBy $by, $text) { @@ -229,7 +231,7 @@ public static function textToBePresentInElement(WebDriverBy $by, $text) * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. - * @return bool WebDriverExpectedCondition Whether the text is present. + * @return WebDriverExpectedCondition Condition returns whether the partial text is present in the element. */ public static function elementTextContains(WebDriverBy $by, $text) { @@ -252,7 +254,7 @@ function (WebDriver $driver) use ($by, $text) { * * @param WebDriverBy $by The locator used to find the element. * @param string $text The expected text of the element. - * @return bool WebDriverExpectedCondition True when element has text value equal to given one + * @return WebDriverExpectedCondition Condition returns whether the element has text value equal to given one. */ public static function elementTextIs(WebDriverBy $by, $text) { @@ -272,7 +274,7 @@ function (WebDriver $driver) use ($by, $text) { * * @param WebDriverBy $by The locator used to find the element. * @param string $regexp The regular expression to test against. - * @return bool WebDriverExpectedCondition True when element has text value equal to given one + * @return WebDriverExpectedCondition Condition returns whether the element has text value equal to given one. */ public static function elementTextMatches(WebDriverBy $by, $regexp) { @@ -292,7 +294,7 @@ function (WebDriver $driver) use ($by, $regexp) { * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element value. - * @return bool WebDriverExpectedCondition Whether the text is presented. + * @return WebDriverExpectedCondition Condition returns whether the text is present in value attribute. */ public static function textToBePresentInElementValue(WebDriverBy $by, $text) { @@ -314,8 +316,8 @@ function (WebDriver $driver) use ($by, $text) { * * @param string $frame_locator The locator used to find the iFrame * expected to be either the id or name value of the i/frame - * @return WebDriverExpectedCondition object focused on new frame - * when frame is found bool false otherwise + * @return WebDriverExpectedCondition Condition returns object focused on new frame when frame is + * found, false otherwise. */ public static function frameToBeAvailableAndSwitchToIt($frame_locator) { @@ -334,7 +336,7 @@ function (WebDriver $driver) use ($frame_locator) { * An expectation for checking that an element is either invisible or not present on the DOM. * * @param WebDriverBy $by The locator used to find the element. - * @return bool WebDriverExpectedCondition Whether there is no element located. + * @return WebDriverExpectedCondition Condition returns whether no visible element located. */ public static function invisibilityOfElementLocated(WebDriverBy $by) { @@ -356,7 +358,7 @@ function (WebDriver $driver) use ($by) { * * @param WebdriverBy $by The locator used to find the element. * @param string $text The text of the element. - * @return bool WebDriverExpectedCondition Whether the text is found in the element located. + * @return WebDriverExpectedCondition Condition returns whether the text is found in the element located. */ public static function invisibilityOfElementWithText(WebDriverBy $by, $text) { @@ -377,8 +379,8 @@ function (WebDriver $driver) use ($by, $text) { * An expectation for checking an element is visible and enabled such that you can click it. * * @param WebDriverBy $by The locator used to find the element - * @return WebDriverExpectedCondition The WebDriverElement - * once it is located, visible and clickable + * @return WebDriverExpectedCondition Condition return the WebDriverElement once it is located, + * visible and clickable. */ public static function elementToBeClickable(WebDriverBy $by) { @@ -408,7 +410,7 @@ function (WebDriver $driver) use ($visibility_of_element_located) { * Wait until an element is no longer attached to the DOM. * * @param WebDriverElement $element The element to wait for. - * @return bool WebDriverExpectedCondition false if the element is still attached to the DOM, true otherwise. + * @return WebDriverExpectedCondition Condition returns whether the element is still attached to the DOM. */ public static function stalenessOf(WebDriverElement $element) { @@ -434,7 +436,8 @@ function () use ($element) { * the condition is checked. * * @param WebDriverExpectedCondition $condition The condition wrapped. - * @return WebDriverExpectedCondition The return value of the getApply() of the given condition. + * @return WebDriverExpectedCondition Condition returns the return value of the getApply() of the given + * condition. */ public static function refreshed(WebDriverExpectedCondition $condition) { @@ -453,7 +456,7 @@ function (WebDriver $driver) use ($condition) { * An expectation for checking if the given element is selected. * * @param mixed $element_or_by Either the element or the locator. - * @return bool WebDriverExpectedCondition whether the element is selected. + * @return WebDriverExpectedCondition Condition returns whether the element is selected. */ public static function elementToBeSelected($element_or_by) { @@ -468,7 +471,7 @@ public static function elementToBeSelected($element_or_by) * * @param mixed $element_or_by Either the element or the locator. * @param bool $selected The required state. - * @return bool WebDriverExpectedCondition Whether the element is selected. + * @return WebDriverExpectedCondition Condition returns whether the element is selected. */ public static function elementSelectionStateToBe($element_or_by, $selected) { @@ -498,7 +501,8 @@ function (WebDriver $driver) use ($element_or_by, $selected) { /** * An expectation for whether an alert() box is present. * - * @return WebDriverExpectedCondition if alert() is present, null otherwise. + * @return WebDriverExpectedCondition Condition returns WebDriverAlert if alert() is present, + * null otherwise. */ public static function alertIsPresent() { diff --git a/tests/unit/Exception/WebDriverExceptionTest.php b/tests/unit/Exception/WebDriverExceptionTest.php index fb25eced2..1dfd94fac 100644 --- a/tests/unit/Exception/WebDriverExceptionTest.php +++ b/tests/unit/Exception/WebDriverExceptionTest.php @@ -35,7 +35,7 @@ public function testShouldThrowProperExceptionBasedOnSeleniumStatusCode($statusC { try { WebDriverException::throwException($statusCode, 'exception message', ['results']); - } catch (\Exception $e) { + } catch (WebDriverException $e) { $this->assertInstanceOf($expectedExceptionType, $e); $this->assertSame('exception message', $e->getMessage()); From 4066768b1a1e6e29a5f2b3eabd22349543dd97a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 13 Jan 2017 15:47:37 +0100 Subject: [PATCH 103/600] We should not change WebDriver interface (it would be an BC break) --- lib/WebDriver.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/WebDriver.php b/lib/WebDriver.php index 48aeefa6b..1c5b59418 100755 --- a/lib/WebDriver.php +++ b/lib/WebDriver.php @@ -130,8 +130,9 @@ public function switchTo(); /** * @return WebDriverTouchScreen + * @todo Add in next major release (BC) */ - public function getTouch(); + //public function getTouch(); /** * @param string $name From cd4f352735552cb36bfcdb5f314846b8c34a32ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 13 Jan 2017 16:08:59 +0100 Subject: [PATCH 104/600] Also do not change RemoteWebDriver interface (it would be an BC break as well) --- lib/Remote/RemoteWebDriver.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index c2ecd8d37..6942c117a 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -20,6 +20,7 @@ use Facebook\WebDriver\WebDriver; use Facebook\WebDriver\WebDriverBy; use Facebook\WebDriver\WebDriverCapabilities; +use Facebook\WebDriver\WebDriverCommandExecutor; use Facebook\WebDriver\WebDriverElement; use Facebook\WebDriver\WebDriverHasInputDevices; use Facebook\WebDriver\WebDriverNavigation; @@ -507,10 +508,10 @@ protected function newElement($id) * @deprecated To be removed in the future. Executor should be passed in the constructor. * @internal * @codeCoverageIgnore - * @param HttpCommandExecutor $executor + * @param WebDriverCommandExecutor $executor Despite the typehint, it have be an instance of HttpCommandExecutor. * @return RemoteWebDriver */ - public function setCommandExecutor(HttpCommandExecutor $executor) + public function setCommandExecutor(WebDriverCommandExecutor $executor) { $this->executor = $executor; From 77300c4ab2025d4316635f592ec849ca7323bd8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 13 Jan 2017 16:48:08 +0100 Subject: [PATCH 105/600] Release version 1.3.0 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 112936c86..04ce2d4dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.3.0 - 2017-01-13 ### Added - Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. - Added option to pass required capabilities when creating `RemoteWebDriver`. (So far only desired capabilities were supported.) @@ -14,7 +16,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - `elementTextContains` (as an alias for `textToBePresentInElement`) - text in element contains given text - `elementTextMatches` - text in element matches regular expression - `numberOfWindowsToBe` - number of opened windows equals given number -- Possibility to select option of `` by its partial text (using `selectByVisiblePartialText()`). - `XPathEscaper` helper class to quote XPaths containing both single and double quotes. - `WebDriverSelectInterface`, to allow implementation of custom select-like components, eg. those not built around and actual select tag. @@ -22,7 +24,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - `Symfony\Process` is used to start local WebDriver processes (when browsers are run directly, without Selenium server) to workaround some PHP bugs and improve portability. - Clarified meaning of selenium server URL variable in methods of `RemoteWebDriver` class. - Deprecated `setSessionID()` and `setCommandExecutor()` methods of `RemoteWebDriver` class; these values should be immutable and thus passed only via constructor. -- Deprecated `WebDriverExpectedCondition::textToBePresentInElement()` in favor of `elementTextContains()` +- Deprecated `WebDriverExpectedCondition::textToBePresentInElement()` in favor of `elementTextContains()`. - Throw an exception when attempting to deselect options of non-multiselect (it already didn't have any effect, but was silently ignored). - Optimize performance of `(de)selectByIndex()` and `getAllSelectedOptions()` methods of `WebDriverSelect` when used with non-multiple select element. From 62223d89bcdd4f755a62b2fbc193122e880c41fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 15 Jan 2017 00:50:02 +0100 Subject: [PATCH 106/600] Minor codestyle fixes --- lib/Remote/HttpCommandExecutor.php | 2 +- lib/Remote/RemoteTargetLocator.php | 2 +- lib/Support/Events/EventFiringWebDriver.php | 16 ++++++++-------- .../Events/EventFiringWebDriverNavigation.php | 12 ++++++++---- lib/WebDriverDispatcher.php | 2 +- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index defb51669..2f6c1778f 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -154,7 +154,7 @@ public function __construct($url, $http_proxy = null, $http_proxy_port = null) if (!empty($http_proxy)) { curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy); - if (!empty($http_proxy_port)) { + if ($http_proxy_port !== null) { curl_setopt($this->curl, CURLOPT_PROXYPORT, $http_proxy_port); } } diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 9b4fe2526..5c218075d 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -79,7 +79,7 @@ public function frame($frame) * Switch the focus to another window by its handle. * * @param string $handle The handle of the window to be focused on. - * @return WebDriver Tge driver focused on the given window. + * @return WebDriver The driver focused on the given window. * @see WebDriver::getWindowHandles */ public function window($handle) diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index 34514e9cd..0dd805bcb 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -398,14 +398,6 @@ public function getTouch() } } - /** - * @param WebDriverException $exception - */ - private function dispatchOnException(WebDriverException $exception) - { - $this->dispatch('onException', $exception, $this); - } - public function execute($name, $params) { try { @@ -415,4 +407,12 @@ public function execute($name, $params) throw $exception; } } + + /** + * @param WebDriverException $exception + */ + private function dispatchOnException(WebDriverException $exception) + { + $this->dispatch('onException', $exception, $this); + } } diff --git a/lib/Support/Events/EventFiringWebDriverNavigation.php b/lib/Support/Events/EventFiringWebDriverNavigation.php index a588d5e17..34bc196ae 100644 --- a/lib/Support/Events/EventFiringWebDriverNavigation.php +++ b/lib/Support/Events/EventFiringWebDriverNavigation.php @@ -38,8 +38,6 @@ public function __construct(WebDriverNavigation $navigator, WebDriverDispatcher { $this->navigator = $navigator; $this->dispatcher = $dispatcher; - - return $this; } /** @@ -130,6 +128,7 @@ public function refresh() return $this; } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } } @@ -145,11 +144,14 @@ public function to($url) $url, $this->getDispatcher()->getDefaultDriver() ); + try { $this->navigator->to($url); } catch (WebDriverException $exception) { $this->dispatchOnException($exception); + throw $exception; } + $this->dispatch( 'afterNavigateTo', $url, @@ -159,9 +161,11 @@ public function to($url) return $this; } - private function dispatchOnException($exception) + /** + * @param WebDriverException $exception + */ + private function dispatchOnException(WebDriverException $exception) { $this->dispatch('onException', $exception); - throw $exception; } } diff --git a/lib/WebDriverDispatcher.php b/lib/WebDriverDispatcher.php index 782c84690..65e0f688d 100644 --- a/lib/WebDriverDispatcher.php +++ b/lib/WebDriverDispatcher.php @@ -26,7 +26,7 @@ class WebDriverDispatcher /** * @var EventFiringWebDriver */ - protected $driver = null; + protected $driver; /** * this is needed so that EventFiringWebElement can pass the driver to the From 43e17c76e23bf927836ff03ea72a46dd4fc321cc Mon Sep 17 00:00:00 2001 From: trotskyist Date: Wed, 3 Jun 2015 13:58:07 -0400 Subject: [PATCH 107/600] Fix an apparent typo in the doc comment to window() method --- lib/WebDriverTargetLocator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WebDriverTargetLocator.php b/lib/WebDriverTargetLocator.php index d9fdf5c18..e6e5dabc5 100644 --- a/lib/WebDriverTargetLocator.php +++ b/lib/WebDriverTargetLocator.php @@ -41,7 +41,7 @@ public function frame($frame); * Switch the focus to another window by its handle. * * @param string $handle The handle of the window to be focused on. - * @return WebDriver Tge driver focused on the given window. + * @return WebDriver The driver focused on the given window. * @see WebDriver::getWindowHandles */ public function window($handle); From 232684ee8ad676618733c918a0d668e02d6bd339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 15 Jan 2017 13:14:39 +0100 Subject: [PATCH 108/600] Upgrade php-cs-fixer to version 2.0 --- .php_cs | 65 ------------------------------------------------ .php_cs.dist | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ composer.json | 4 +-- 3 files changed, 71 insertions(+), 67 deletions(-) delete mode 100644 .php_cs create mode 100644 .php_cs.dist diff --git a/.php_cs b/.php_cs deleted file mode 100644 index 0466edfbe..000000000 --- a/.php_cs +++ /dev/null @@ -1,65 +0,0 @@ -in([__DIR__ . '/lib', __DIR__ . '/tests']); - -return Symfony\CS\Config\Config::create() - ->fixers([ - 'array_element_white_space_after_comma', - 'duplicate_semicolon', - 'extra_empty_lines', - 'function_typehint_space', - 'lowercase_cast', - 'method_argument_default_value', - 'multiline_array_trailing_comma', - 'namespace_no_leading_whitespace', - 'native_function_casing', - 'new_with_braces', - 'no_blank_lines_after_class_opening', - 'no_empty_lines_after_phpdocs', - 'no_empty_phpdoc', - 'no_empty_statement', - 'object_operator', - 'operators_spaces', - 'trim_array_spaces', - 'phpdoc_indent', - 'phpdoc_no_access', - 'phpdoc_no_empty_return', - 'phpdoc_no_package', - 'phpdoc_scalar', - 'phpdoc_single_line_var_spacing', - 'phpdoc_trim', - 'phpdoc_types', - 'phpdoc_order', - 'unused_use', - 'ordered_use', - 'remove_leading_slash_use', - 'remove_lines_between_uses', - 'return', - 'self_accessor', - 'single_array_no_trailing_comma', - 'single_blank_line_before_namespace', - 'single_quote', - 'spaces_after_semicolon', - 'spaces_before_semicolon', - 'spaces_cast', - 'standardize_not_equal', - 'ternary_spaces', - 'trim_array_spaces', - 'unary_operators_spaces', - 'unused_use', - 'whitespacy_lines', - - // additional contrib checks - 'concat_with_spaces', - 'newline_after_open_tag', - 'no_useless_else', - 'no_useless_return', - 'php_unit_construct', - 'php_unit_dedicate_assert', - 'phpdoc_order', - 'short_array_syntax', - ]) - ->level(Symfony\CS\FixerInterface::PSR2_LEVEL) - ->setUsingCache(true) - ->finder($finder); diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 000000000..deb2dc803 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,69 @@ +in([__DIR__ . '/lib', __DIR__ . '/tests']); + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => true, + 'blank_line_before_return' => true, + 'cast_spaces' => true, + 'concat_space' => ['spacing' => 'one'], + 'function_typehint_space' => true, + 'linebreak_after_opening_tag' => true, + 'lowercase_cast' => true, + 'native_function_casing' => true, + 'new_with_braces' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_consecutive_blank_lines' => [ + 'use', + 'break', + 'continue', + 'extra', + 'return', + 'throw', + 'useTrait', + 'curly_brace_block', + 'parenthesis_brace_block', + 'square_brace_block', + ], + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'no_whitespace_in_blank_line' => true, + 'object_operator_without_whitespace' => true, + 'ordered_imports' => true, + 'php_unit_construct' => true, + 'php_unit_dedicate_assert' => true, + 'phpdoc_indent' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_order' => true, + 'phpdoc_scalar' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'self_accessor' => true, + 'single_blank_line_before_namespace' => true, + 'single_quote' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'trailing_comma_in_multiline_array' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'whitespace_after_comma_in_array' => true, + ]) + ->setRiskyAllowed(true) + ->setFinder($finder); diff --git a/composer.json b/composer.json index 55780368b..557b0c908 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "facebook/webdriver", - "description": "A PHP client for WebDriver", + "description": "A PHP client for Selenium WebDriver", "keywords": ["webdriver", "selenium", "php", "facebook"], "homepage": "https://github.com/facebook/php-webdriver", "type": "library", @@ -17,7 +17,7 @@ }, "require-dev": { "phpunit/phpunit": "4.6.* || ~5.0", - "friendsofphp/php-cs-fixer": "^1.11", + "friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", "satooshi/php-coveralls": "^1.0" From 3e64225dad97b72551e48eb85a63b526acd51b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 15 Jan 2017 13:34:38 +0100 Subject: [PATCH 109/600] Add new php-cs-fixer checks; use multibyte string functions --- .php_cs.dist | 7 +++++++ lib/Chrome/ChromeDriver.php | 8 ++++++++ lib/Firefox/FirefoxProfile.php | 2 +- lib/Remote/RemoteWebElement.php | 2 +- lib/Support/XPathEscaper.php | 4 ++-- lib/WebDriver.php | 8 ++++---- lib/WebDriverExpectedCondition.php | 8 ++++---- lib/WebDriverOptions.php | 4 ++-- lib/WebDriverWindow.php | 2 +- 9 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index deb2dc803..0d4568a4b 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -14,10 +14,14 @@ return PhpCsFixer\Config::create() 'function_typehint_space' => true, 'linebreak_after_opening_tag' => true, 'lowercase_cast' => true, + 'mb_str_functions' => true, + 'method_separation' => true, 'native_function_casing' => true, 'new_with_braces' => true, + 'no_alias_functions' => true, 'no_blank_lines_after_class_opening' => true, 'no_blank_lines_after_phpdoc' => true, + 'no_empty_comment' => true, 'no_empty_phpdoc' => true, 'no_empty_statement' => true, 'no_extra_consecutive_blank_lines' => [ @@ -45,6 +49,7 @@ return PhpCsFixer\Config::create() 'ordered_imports' => true, 'php_unit_construct' => true, 'php_unit_dedicate_assert' => true, + 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_indent' => true, 'phpdoc_no_access' => true, 'phpdoc_no_empty_return' => true, @@ -54,7 +59,9 @@ return PhpCsFixer\Config::create() 'phpdoc_single_line_var_spacing' => true, 'phpdoc_trim' => true, 'phpdoc_types' => true, + 'psr4' => true, 'self_accessor' => true, + 'short_scalar_cast' => true, 'single_blank_line_before_namespace' => true, 'single_quote' => true, 'space_after_semicolon' => true, diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 249c4f1b5..8ba76583c 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -55,7 +55,15 @@ public function startSession(DesiredCapabilities $desired_capabilities) /** * Always throws an exception. Use ChromeDriver::start() instead. * + * @param string $selenium_server_url + * @param DesiredCapabilities|array $desired_capabilities + * @param int|null $connection_timeout_in_ms + * @param int|null $request_timeout_in_ms + * @param string|null $http_proxy + * @param int|null $http_proxy_port + * @param DesiredCapabilities $required_capabilities * @throws WebDriverException + * @return RemoteWebDriver */ public static function create( $selenium_server_url = 'http://localhost:4444/wd/hub', diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 00dcebd5c..8086198ca 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -211,7 +211,7 @@ private function installExtension($extension, $profile_dir) $prefix = ''; if (!empty($ns)) { foreach ($ns as $key => $value) { - if (strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) { + if (mb_strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) { if ($key != '') { $prefix = $key . ':'; // Separate the namespace from the name. } diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index dfc66d124..a7fbf6834 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -254,7 +254,7 @@ public function getTagName() // until this issue is not resolved : // https://github.com/operasoftware/operadriver/issues/102 // Remove it when fixed to be consistent with the protocol. - return strtolower($this->executor->execute( + return mb_strtolower($this->executor->execute( DriverCommand::GET_ELEMENT_TAG_NAME, [':id' => $this->id] )); diff --git a/lib/Support/XPathEscaper.php b/lib/Support/XPathEscaper.php index 10271128c..dc5907f01 100644 --- a/lib/Support/XPathEscaper.php +++ b/lib/Support/XPathEscaper.php @@ -27,12 +27,12 @@ class XPathEscaper public static function escapeQuotes($xpathToEscape) { // Single quotes not present => we can quote in them - if (strpos($xpathToEscape, "'") === false) { + if (mb_strpos($xpathToEscape, "'") === false) { return sprintf("'%s'", $xpathToEscape); } // Double quotes not present => we can quote in them - if (strpos($xpathToEscape, '"') === false) { + if (mb_strpos($xpathToEscape, '"') === false) { return sprintf('"%s"', $xpathToEscape); } diff --git a/lib/WebDriver.php b/lib/WebDriver.php index 1c5b59418..ea413f883 100755 --- a/lib/WebDriver.php +++ b/lib/WebDriver.php @@ -128,10 +128,10 @@ public function navigate(); */ public function switchTo(); - /** - * @return WebDriverTouchScreen - * @todo Add in next major release (BC) - */ + ///** + // * @return WebDriverTouchScreen + // * @todo Add in next major release (BC) + // */ //public function getTouch(); /** diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 930a13733..baee93e85 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -72,7 +72,7 @@ public static function titleContains($title) { return new static( function (WebDriver $driver) use ($title) { - return strpos($driver->getTitle(), $title) !== false; + return mb_strpos($driver->getTitle(), $title) !== false; } ); } @@ -118,7 +118,7 @@ public static function urlContains($url) { return new static( function (WebDriver $driver) use ($url) { - return strpos($driver->getCurrentURL(), $url) !== false; + return mb_strpos($driver->getCurrentURL(), $url) !== false; } ); } @@ -240,7 +240,7 @@ function (WebDriver $driver) use ($by, $text) { try { $element_text = $driver->findElement($by)->getText(); - return strpos($element_text, $text) !== false; + return mb_strpos($element_text, $text) !== false; } catch (StaleElementReferenceException $e) { return null; } @@ -303,7 +303,7 @@ function (WebDriver $driver) use ($by, $text) { try { $element_text = $driver->findElement($by)->getAttribute('value'); - return strpos($element_text, $text) !== false; + return mb_strpos($element_text, $text) !== false; } catch (StaleElementReferenceException $e) { return null; } diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index fef36f695..bdf4db2ae 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -123,7 +123,7 @@ private function validate(array $cookie) { if (!isset($cookie['name']) || $cookie['name'] === '' || - strpos($cookie['name'], ';') !== false + mb_strpos($cookie['name'], ';') !== false ) { throw new InvalidArgumentException( '"name" should be non-empty and does not contain a ";"' @@ -136,7 +136,7 @@ private function validate(array $cookie) ); } - if (isset($cookie['domain']) && strpos($cookie['domain'], ':') !== false) { + if (isset($cookie['domain']) && mb_strpos($cookie['domain'], ':') !== false) { throw new InvalidArgumentException( '"domain" should not contain a port:' . (string) $cookie['domain'] ); diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index d48a70773..6b9090a99 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -145,7 +145,7 @@ public function getScreenOrientation() */ public function setScreenOrientation($orientation) { - $orientation = strtoupper($orientation); + $orientation = mb_strtoupper($orientation); if (!in_array($orientation, ['PORTRAIT', 'LANDSCAPE'])) { throw new IndexOutOfBoundsException( 'Orientation must be either PORTRAIT, or LANDSCAPE' From 04aab9f79dc5ac34d1c727fff46fc491350b4c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 15 Jan 2017 13:42:38 +0100 Subject: [PATCH 110/600] Rearrange class methods order to match the standard one (public > protected > private) --- .php_cs.dist | 1 + lib/Remote/DesiredCapabilities.php | 48 +++---- lib/Remote/RemoteWebDriver.php | 132 +++++++++--------- lib/Remote/RemoteWebElement.php | 72 +++++----- lib/Support/Events/EventFiringWebDriver.php | 48 +++---- .../Events/EventFiringWebDriverNavigation.php | 30 ++-- lib/Support/Events/EventFiringWebElement.php | 46 +++--- lib/WebDriverExpectedCondition.php | 10 +- lib/WebDriverOptions.php | 45 +++--- 9 files changed, 214 insertions(+), 218 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 0d4568a4b..c40510179 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -46,6 +46,7 @@ return PhpCsFixer\Config::create() 'no_useless_return' => true, 'no_whitespace_in_blank_line' => true, 'object_operator_without_whitespace' => true, + 'ordered_class_elements' => true, 'ordered_imports' => true, 'php_unit_construct' => true, 'php_unit_dedicate_assert' => true, diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index badd04313..12060ab7b 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -175,30 +175,6 @@ public function toArray() return $this->capabilities; } - /** - * @param string $key - * @param mixed $value - * @return DesiredCapabilities - */ - private function set($key, $value) - { - $this->capabilities[$key] = $value; - - return $this; - } - - /** - * @param string $key - * @param mixed $default - * @return mixed - */ - private function get($key, $default = null) - { - return isset($this->capabilities[$key]) - ? $this->capabilities[$key] - : $default; - } - /** * @return DesiredCapabilities */ @@ -339,4 +315,28 @@ public static function phantomjs() WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, ]); } + + /** + * @param string $key + * @param mixed $value + * @return DesiredCapabilities + */ + private function set($key, $value) + { + $this->capabilities[$key] = $value; + + return $this; + } + + /** + * @param string $key + * @param mixed $default + * @return mixed + */ + private function get($key, $default = null) + { + return isset($this->capabilities[$key]) + ? $this->capabilities[$key] + : $default; + } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 6942c117a..a06beb132 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -126,26 +126,6 @@ public static function create( return $driver; } - /** - * Cast legacy types (array or null) to DesiredCapabilities object. To be removed in future when instance of - * DesiredCapabilities will be required. - * - * @param array|DesiredCapabilities|null $desired_capabilities - * @return DesiredCapabilities - */ - protected static function castToDesiredCapabilitiesObject($desired_capabilities = null) - { - if ($desired_capabilities === null) { - return new DesiredCapabilities(); - } - - if (is_array($desired_capabilities)) { - return new DesiredCapabilities($desired_capabilities); - } - - return $desired_capabilities; - } - /** * [Experimental] Construct the RemoteWebDriver by an existing session. * @@ -293,29 +273,6 @@ public function quit() $this->executor = null; } - /** - * Prepare arguments for JavaScript injection - * - * @param array $arguments - * @return array - */ - private function prepareScriptArguments(array $arguments) - { - $args = []; - foreach ($arguments as $key => $value) { - if ($value instanceof WebDriverElement) { - $args[$key] = ['ELEMENT' => $value->getID()]; - } else { - if (is_array($value)) { - $value = $this->prepareScriptArguments($value); - } - $args[$key] = $value; - } - } - - return $args; - } - /** * Inject a snippet of JavaScript into the page for execution in the context * of the currently selected frame. The executed script is assumed to be @@ -469,18 +426,6 @@ public function getTouch() return $this->touch; } - /** - * @return RemoteExecuteMethod - */ - protected function getExecuteMethod() - { - if (!$this->executeMethod) { - $this->executeMethod = new RemoteExecuteMethod($this); - } - - return $this->executeMethod; - } - /** * Construct a new action builder. * @@ -491,17 +436,6 @@ public function action() return new WebDriverActions($this); } - /** - * Return the WebDriverElement with the given id. - * - * @param string $id The id of the element to be created. - * @return RemoteWebElement - */ - protected function newElement($id) - { - return new RemoteWebElement($this->getExecuteMethod(), $id); - } - /** * Set the command executor of this RemoteWebdriver * @@ -601,4 +535,70 @@ public function execute($command_name, $params = []) return null; } + + /** + * Prepare arguments for JavaScript injection + * + * @param array $arguments + * @return array + */ + protected function prepareScriptArguments(array $arguments) + { + $args = []; + foreach ($arguments as $key => $value) { + if ($value instanceof WebDriverElement) { + $args[$key] = ['ELEMENT' => $value->getID()]; + } else { + if (is_array($value)) { + $value = $this->prepareScriptArguments($value); + } + $args[$key] = $value; + } + } + + return $args; + } + + /** + * @return RemoteExecuteMethod + */ + protected function getExecuteMethod() + { + if (!$this->executeMethod) { + $this->executeMethod = new RemoteExecuteMethod($this); + } + + return $this->executeMethod; + } + + /** + * Return the WebDriverElement with the given id. + * + * @param string $id The id of the element to be created. + * @return RemoteWebElement + */ + protected function newElement($id) + { + return new RemoteWebElement($this->getExecuteMethod(), $id); + } + + /** + * Cast legacy types (array or null) to DesiredCapabilities object. To be removed in future when instance of + * DesiredCapabilities will be required. + * + * @param array|DesiredCapabilities|null $desired_capabilities + * @return DesiredCapabilities + */ + protected static function castToDesiredCapabilitiesObject($desired_capabilities = null) + { + if ($desired_capabilities === null) { + return new DesiredCapabilities(); + } + + if (is_array($desired_capabilities)) { + return new DesiredCapabilities($desired_capabilities); + } + + return $desired_capabilities; + } } diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index a7fbf6834..c10bfbf32 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -342,42 +342,6 @@ public function sendKeys($value) return $this; } - /** - * Upload a local file to the server - * - * @param string $local_file - * - * @throws WebDriverException - * @return string The remote path of the file. - */ - private function upload($local_file) - { - if (!is_file($local_file)) { - throw new WebDriverException('You may only upload files: ' . $local_file); - } - - // Create a temporary file in the system temp directory. - $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip'); - $zip = new ZipArchive(); - if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) { - return false; - } - $info = pathinfo($local_file); - $file_name = $info['basename']; - $zip->addFile($local_file, $file_name); - $zip->close(); - $params = [ - 'file' => base64_encode(file_get_contents($temp_zip)), - ]; - $remote_path = $this->executor->execute( - DriverCommand::UPLOAD_FILE, - $params - ); - unlink($temp_zip); - - return $remote_path; - } - /** * Set the fileDetector in order to let the RemoteWebElement to know that * you are going to upload a file. @@ -450,4 +414,40 @@ protected function newElement($id) { return new static($this->executor, $id); } + + /** + * Upload a local file to the server + * + * @param string $local_file + * + * @throws WebDriverException + * @return string The remote path of the file. + */ + protected function upload($local_file) + { + if (!is_file($local_file)) { + throw new WebDriverException('You may only upload files: ' . $local_file); + } + + // Create a temporary file in the system temp directory. + $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip'); + $zip = new ZipArchive(); + if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) { + return false; + } + $info = pathinfo($local_file); + $file_name = $info['basename']; + $zip->addFile($local_file, $file_name); + $zip->close(); + $params = [ + 'file' => base64_encode(file_get_contents($temp_zip)), + ]; + $remote_path = $this->executor->execute( + DriverCommand::UPLOAD_FILE, + $params + ); + unlink($temp_zip); + + return $remote_path; + } } diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index 0dd805bcb..ffac00e5c 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -60,20 +60,6 @@ public function getDispatcher() return $this->dispatcher; } - /** - * @param mixed $method - */ - protected function dispatch($method) - { - if (!$this->dispatcher) { - return; - } - - $arguments = func_get_args(); - unset($arguments[0]); - $this->dispatcher->dispatch($method, $arguments); - } - /** * @return WebDriver */ @@ -82,15 +68,6 @@ public function getWebDriver() return $this->driver; } - /** - * @param WebDriverElement $element - * @return EventFiringWebElement - */ - protected function newElement(WebDriverElement $element) - { - return new EventFiringWebElement($element, $this->getDispatcher()); - } - /** * @param mixed $url * @throws WebDriverException @@ -408,10 +385,33 @@ public function execute($name, $params) } } + /** + * @param WebDriverElement $element + * @return EventFiringWebElement + */ + protected function newElement(WebDriverElement $element) + { + return new EventFiringWebElement($element, $this->getDispatcher()); + } + + /** + * @param mixed $method + */ + protected function dispatch($method) + { + if (!$this->dispatcher) { + return; + } + + $arguments = func_get_args(); + unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); + } + /** * @param WebDriverException $exception */ - private function dispatchOnException(WebDriverException $exception) + protected function dispatchOnException(WebDriverException $exception) { $this->dispatch('onException', $exception, $this); } diff --git a/lib/Support/Events/EventFiringWebDriverNavigation.php b/lib/Support/Events/EventFiringWebDriverNavigation.php index 34bc196ae..5aeaf510b 100644 --- a/lib/Support/Events/EventFiringWebDriverNavigation.php +++ b/lib/Support/Events/EventFiringWebDriverNavigation.php @@ -48,20 +48,6 @@ public function getDispatcher() return $this->dispatcher; } - /** - * @param mixed $method - */ - protected function dispatch($method) - { - if (!$this->dispatcher) { - return; - } - - $arguments = func_get_args(); - unset($arguments[0]); - $this->dispatcher->dispatch($method, $arguments); - } - /** * @return WebDriverNavigation */ @@ -161,10 +147,24 @@ public function to($url) return $this; } + /** + * @param mixed $method + */ + protected function dispatch($method) + { + if (!$this->dispatcher) { + return; + } + + $arguments = func_get_args(); + unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); + } + /** * @param WebDriverException $exception */ - private function dispatchOnException(WebDriverException $exception) + protected function dispatchOnException(WebDriverException $exception) { $this->dispatch('onException', $exception); } diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index b9591b0ef..f932b20a3 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -53,19 +53,6 @@ public function getDispatcher() return $this->dispatcher; } - /** - * @param mixed $method - */ - protected function dispatch($method) - { - if (!$this->dispatcher) { - return; - } - $arguments = func_get_args(); - unset($arguments[0]); - $this->dispatcher->dispatch($method, $arguments); - } - /** * @return WebDriverElement */ @@ -74,15 +61,6 @@ public function getElement() return $this->element; } - /** - * @param WebDriverElement $element - * @return EventFiringWebElement - */ - protected function newElement(WebDriverElement $element) - { - return new static($element, $this->getDispatcher()); - } - /** * @param mixed $value * @throws WebDriverException @@ -403,7 +381,7 @@ public function equals(WebDriverElement $other) /** * @param WebDriverException $exception */ - private function dispatchOnException(WebDriverException $exception) + protected function dispatchOnException(WebDriverException $exception) { $this->dispatch( 'onException', @@ -411,4 +389,26 @@ private function dispatchOnException(WebDriverException $exception) $this->dispatcher->getDefaultDriver() ); } + + /** + * @param mixed $method + */ + protected function dispatch($method) + { + if (!$this->dispatcher) { + return; + } + $arguments = func_get_args(); + unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); + } + + /** + * @param WebDriverElement $element + * @return EventFiringWebElement + */ + protected function newElement(WebDriverElement $element) + { + return new static($element, $this->getDispatcher()); + } } diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index baee93e85..58ba939e9 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -34,6 +34,11 @@ class WebDriverExpectedCondition */ private $apply; + protected function __construct(callable $apply) + { + $this->apply = $apply; + } + /** * @return callable A callable function to be executed by WebDriverWait */ @@ -42,11 +47,6 @@ public function getApply() return $this->apply; } - protected function __construct(callable $apply) - { - $this->apply = $apply; - } - /** * An expectation for checking the title of a page. * diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index bdf4db2ae..b728382cc 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -54,7 +54,7 @@ public function __construct(ExecuteMethod $executor) */ public function addCookie(array $cookie) { - $this->validate($cookie); + $this->validateCookie($cookie); $this->executor->execute( DriverCommand::ADD_COOKIE, ['cookie' => $cookie] @@ -119,30 +119,6 @@ public function getCookies() return $this->executor->execute(DriverCommand::GET_ALL_COOKIES); } - private function validate(array $cookie) - { - if (!isset($cookie['name']) || - $cookie['name'] === '' || - mb_strpos($cookie['name'], ';') !== false - ) { - throw new InvalidArgumentException( - '"name" should be non-empty and does not contain a ";"' - ); - } - - if (!isset($cookie['value'])) { - throw new InvalidArgumentException( - '"value" is required when setting a cookie.' - ); - } - - if (isset($cookie['domain']) && mb_strpos($cookie['domain'], ':') !== false) { - throw new InvalidArgumentException( - '"domain" should not contain a port:' . (string) $cookie['domain'] - ); - } - } - /** * Return the interface for managing driver timeouts. * @@ -189,4 +165,23 @@ public function getAvailableLogTypes() { return $this->executor->execute(DriverCommand::GET_AVAILABLE_LOG_TYPES); } + + /** + * @param array $cookie + * @throws \InvalidArgumentException + */ + private function validateCookie(array $cookie) + { + if (!isset($cookie['name']) || $cookie['name'] === '' || mb_strpos($cookie['name'], ';') !== false) { + throw new InvalidArgumentException('"name" should be non-empty and does not contain a ";"'); + } + + if (!isset($cookie['value'])) { + throw new InvalidArgumentException('"value" is required when setting a cookie.'); + } + + if (isset($cookie['domain']) && mb_strpos($cookie['domain'], ':') !== false) { + throw new InvalidArgumentException('"domain" should not contain a port:' . (string) $cookie['domain']); + } + } } From ccab174d84cca426220800be0b79d2efb7065825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 17 Jan 2017 02:50:48 +0100 Subject: [PATCH 111/600] Do not suggest phpdocumentor, the API docs is now generated using Sami --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 55780368b..941a816c3 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,6 @@ "php-mock/php-mock-phpunit": "^1.1", "satooshi/php-coveralls": "^1.0" }, - "suggest": { - "phpdocumentor/phpdocumentor": "2.*" - }, "autoload": { "psr-4": { "Facebook\\WebDriver\\": "lib/" From 37d5925bcb63af1fb409a5e3d9374770f9c6c8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 17 Jan 2017 02:53:58 +0100 Subject: [PATCH 112/600] Update API documentation URL (fixes #378) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc3e9fbb0..37fb7f393 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The concepts of this library are very similar to the "official" Java, .NET, Pyth **This is new version of PHP client, rewritten from scratch starting 2013.** Using the old version? Check out [Adam Goucher's fork](https://github.com/Element-34/php-webdriver) of it. -Looking for API documentation of php-webdriver? See http://facebook.github.io/php-webdriver/ +Looking for API documentation of php-webdriver? See [https://facebook.github.io/php-webdriver/](https://facebook.github.io/php-webdriver/latest/) Any complaint, question, idea? You can post it on the user group https://www.facebook.com/groups/phpwebdriver/. From f3e1c4576feabc76999cb33af63282b6690c3f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 17 Jan 2017 03:32:38 +0100 Subject: [PATCH 113/600] Update links in README, add link to another php-webdriver integrations --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 37fb7f393..d2a8d6132 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,18 @@ For latest changes see [CHANGELOG.md](CHANGELOG.md) file. ## More information -Check out the Selenium docs and wiki at http://docs.seleniumhq.org/docs/ and https://code.google.com/p/selenium/wiki +Some how-tos are provided right here in [our GitHub wiki](https://github.com/facebook/php-webdriver/wiki). -Learn how to integrate it with PHPUnit [Blogpost](http://codeception.com/11-12-2013/working-with-phpunit-and-selenium-webdriver.html) | [Demo Project](https://github.com/DavertMik/php-webdriver-demo) +You may also want to check out the Selenium [docs](http://docs.seleniumhq.org/docs/) and [wiki](https://github.com/SeleniumHQ/selenium/wiki). + +## Testing framework integration + +To take advantage of automatized testing you will most probably want to integrate php-webdriver to your testing framework. +There are some project already providing this: + +- [Steward](https://github.com/lmc-eu/steward) integrates php-webdriver directly to [PHPUnit](https://phpunit.de/), also providers parallelization. +- [Codeception](http://codeception.com) testing framework provides BDD-layer on top of php-webdriver in its [WebDriver module](http://codeception.com/docs/modules/WebDriver). +- You can also check out this [blogpost](http://codeception.com/11-12-2013/working-with-phpunit-and-selenium-webdriver.html) + [demo project](https://github.com/DavertMik/php-webdriver-demo), describing simple [PHPUnit](https://phpunit.de/) integration. ## Support From 1fdbab925e26893ba8a0cb93ddf5c6b613e307a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 20 Jan 2017 20:39:13 +0100 Subject: [PATCH 114/600] Specify covered methods to have more accurate code coverage --- tests/functional/RemoteWebElementTest.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 1a04cf1a8..c74b5d384 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -16,10 +16,13 @@ namespace Facebook\WebDriver; /** - * @covers Facebook\WebDriver\Remote\RemoteWebElement + * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebElement */ class RemoteWebElementTest extends WebDriverTestCase { + /** + * @covers ::getText + */ public function testShouldGetText() { $this->driver->get($this->getTestPath('index.html')); @@ -30,6 +33,9 @@ public function testShouldGetText() $this->assertEquals('Multiple spaces are stripped', $elementWithTextWithSpaces->getText()); } + /** + * @covers ::getAttribute + */ public function testShouldGetAttributeValue() { $this->driver->get($this->getTestPath('index.html')); @@ -41,6 +47,9 @@ public function testShouldGetAttributeValue() $this->assertSame('text-simple', $element->getAttribute('id')); } + /** + * @covers ::getLocation + */ public function testShouldGetLocation() { $this->driver->get($this->getTestPath('index.html')); @@ -53,6 +62,9 @@ public function testShouldGetLocation() $this->assertSame(500, $elementLocation->getY()); } + /** + * @covers ::getSize + */ public function testShouldGetSize() { $this->driver->get($this->getTestPath('index.html')); @@ -65,6 +77,9 @@ public function testShouldGetSize() $this->assertSame(66, $elementSize->getHeight()); } + /** + * @covers ::getCSSValue + */ public function testShouldGetCssValue() { $this->driver->get($this->getTestPath('index.html')); From 4ab3d675cd9bf2714d0841e558db7b00231f968d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 20 Jan 2017 21:20:43 +0100 Subject: [PATCH 115/600] Add more functional tests for RemoteWebElement --- lib/Remote/RemoteWebElement.php | 4 +- tests/functional/RemoteWebElementTest.php | 164 ++++++++++++++++++++++ tests/functional/web/form.html | 28 +++- tests/functional/web/index.html | 7 + tests/functional/web/submit.php | 28 ++++ tests/functional/web/upload.html | 2 +- 6 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 tests/functional/web/submit.php diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index c10bfbf32..71fdb4305 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -244,13 +244,13 @@ public function getSize() } /** - * Get the tag name of this element. + * Get the (lowercase) tag name of this element. * * @return string The tag name. */ public function getTagName() { - // Force tag name to be lowercase as expected by protocol for Opera driver + // Force tag name to be lowercase as expected by JsonWire protocol for Opera driver // until this issue is not resolved : // https://github.com/operasoftware/operadriver/issues/102 // Remove it when fixed to be consistent with the protocol. diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index c74b5d384..48983a14e 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -93,4 +93,168 @@ public function testShouldGetCssValue() $this->assertSame('rgba(0, 0, 0, 1)', $elementWithBorder->getCSSValue('border-left-color')); $this->assertSame('rgba(0, 0, 0, 1)', $elementWithoutBorder->getCSSValue('border-left-color')); } + + /** + * @covers ::getTagName + */ + public function testShouldGetTagName() + { + $this->driver->get($this->getTestPath('index.html')); + + $paragraphElement = $this->driver->findElement(WebDriverBy::id('id_test')); + + $this->assertSame('p', $paragraphElement->getTagName()); + } + + /** + * @covers ::click + */ + public function testShouldClick() + { + $this->driver->get($this->getTestPath('index.html')); + $linkElement = $this->driver->findElement(WebDriverBy::id('a-form')); + + $linkElement->click(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::urlContains('form.html') + ); + } + + /** + * @covers ::clear + */ + public function testShouldClearFormElementText() + { + $this->driver->get($this->getTestPath('form.html')); + + $input = $this->driver->findElement(WebDriverBy::id('input-text')); + $textarea = $this->driver->findElement(WebDriverBy::id('textarea')); + + $this->assertSame('Default input text', $input->getAttribute('value')); + $input->clear(); + $this->assertSame('', $input->getAttribute('value')); + + $this->assertSame('Default textarea text', $textarea->getAttribute('value')); + $textarea->clear(); + $this->assertSame('', $textarea->getAttribute('value')); + } + + /** + * @covers ::sendKeys + */ + public function testShouldSendKeysToFormElement() + { + $this->driver->get($this->getTestPath('form.html')); + + $input = $this->driver->findElement(WebDriverBy::id('input-text')); + $textarea = $this->driver->findElement(WebDriverBy::id('textarea')); + + $input->clear(); + $input->sendKeys('foo bar'); + $this->assertSame('foo bar', $input->getAttribute('value')); + $input->sendKeys(' baz'); + $this->assertSame('foo bar baz', $input->getAttribute('value')); + + $textarea->clear(); + $textarea->sendKeys('foo bar'); + $this->assertSame('foo bar', $textarea->getAttribute('value')); + $textarea->sendKeys(' baz'); + $this->assertSame('foo bar baz', $textarea->getAttribute('value')); + } + + /** + * @covers ::isEnabled + */ + public function testShouldDetectEnabledInputs() + { + $this->driver->get($this->getTestPath('form.html')); + + $inputEnabled = $this->driver->findElement(WebDriverBy::id('input-text')); + $inputDisabled = $this->driver->findElement(WebDriverBy::id('input-text-disabled')); + + $this->assertTrue($inputEnabled->isEnabled()); + $this->assertFalse($inputDisabled->isEnabled()); + } + + /** + * @covers ::isSelected + */ + public function testShouldSelectedInputsOrOptions() + { + $this->driver->get($this->getTestPath('form.html')); + + $checkboxSelected = $this->driver->findElement( + WebDriverBy::cssSelector('input[name=checkbox][value=second]') + ); + $checkboxNotSelected = $this->driver->findElement( + WebDriverBy::cssSelector('input[name=checkbox][value=first]') + ); + $this->assertTrue($checkboxSelected->isSelected()); + $this->assertFalse($checkboxNotSelected->isSelected()); + + $radioSelected = $this->driver->findElement(WebDriverBy::cssSelector('input[name=radio][value=second]')); + $radioNotSelected = $this->driver->findElement(WebDriverBy::cssSelector('input[name=radio][value=first]')); + $this->assertTrue($radioSelected->isSelected()); + $this->assertFalse($radioNotSelected->isSelected()); + + $optionSelected = $this->driver->findElement(WebDriverBy::cssSelector('#select option[value=first]')); + $optionNotSelected = $this->driver->findElement(WebDriverBy::cssSelector('#select option[value=second]')); + $this->assertTrue($optionSelected->isSelected()); + $this->assertFalse($optionNotSelected->isSelected()); + } + + /** + * @covers ::submit + */ + public function testShouldSubmitFormBySubmitEventOnForm() + { + $this->driver->get($this->getTestPageUrl('form.html')); + + $formElement = $this->driver->findElement(WebDriverBy::cssSelector('form')); + + $formElement->submit(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::titleIs('Form submit endpoint') + ); + + $this->assertSame('Received POST data', $this->driver->findElement(WebDriverBy::cssSelector('h2'))->getText()); + } + + /** + * @covers ::submit + */ + public function testShouldSubmitFormBySubmitEventOnFormInputElement() + { + $this->driver->get($this->getTestPageUrl('form.html')); + + $inputTextElement = $this->driver->findElement(WebDriverBy::id('input-text')); + + $inputTextElement->submit(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::titleIs('Form submit endpoint') + ); + + $this->assertSame('Received POST data', $this->driver->findElement(WebDriverBy::cssSelector('h2'))->getText()); + } + + /** + * @covers ::click + */ + public function testShouldSubmitFormByClickOnSubmitInput() + { + $this->driver->get($this->getTestPageUrl('form.html')); + + $submitElement = $this->driver->findElement(WebDriverBy::id('submit')); + + $submitElement->click(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::titleIs('Form submit endpoint') + ); + + $this->assertSame('Received POST data', $this->driver->findElement(WebDriverBy::cssSelector('h2'))->getText()); + } } diff --git a/tests/functional/web/form.html b/tests/functional/web/form.html index ac91336b1..c1570df8a 100644 --- a/tests/functional/web/form.html +++ b/tests/functional/web/form.html @@ -5,16 +5,22 @@ php-webdriver form test page -
    + +
    + +

    @@ -38,6 +44,22 @@
    +
    + Checkboxes + First
    + Second (preselected)
    + Third (preselected)
    + Fourth
    +
    + +
    + Radio buttons + First
    + Second (preselected)
    + Third
    + Fourth
    +
    +

    diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index 282706cce..f0dc03af4 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -6,6 +6,13 @@

    Welcome to the facebook/php-webdriver testing page.

    + + Form test page + | + Form with file upload + | + New window opener test page +

    Test by ID

    Test by Class

    Click here diff --git a/tests/functional/web/submit.php b/tests/functional/web/submit.php new file mode 100644 index 000000000..4d8219ec5 --- /dev/null +++ b/tests/functional/web/submit.php @@ -0,0 +1,28 @@ + + + + + Form submit endpoint + + + +POST data not detected'; +} else { + echo '

    Received POST data

    '; + echo '
      '; + foreach ($_POST as $key => $value) { + echo sprintf( + '
    • %s: %s
    • ' . "\n", + $key, + $key, + $value + ); + } + echo '
    '; +} +?> + + + diff --git a/tests/functional/web/upload.html b/tests/functional/web/upload.html index d02c5ed4b..65a622c50 100644 --- a/tests/functional/web/upload.html +++ b/tests/functional/web/upload.html @@ -5,7 +5,7 @@ Upload a file - +

    From c8e3f5ac5015773691b92bf224a11909a38a338f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 20 Jan 2017 21:25:51 +0100 Subject: [PATCH 116/600] Test equals() method of RemoteWebElementTest --- tests/functional/RemoteWebElementTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 48983a14e..e5d1ead06 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -257,4 +257,23 @@ public function testShouldSubmitFormByClickOnSubmitInput() $this->assertSame('Received POST data', $this->driver->findElement(WebDriverBy::cssSelector('h2'))->getText()); } + + /** + * @covers ::equals + */ + public function testShouldCompareEqualsElement() + { + $this->driver->get($this->getTestPath('index.html')); + + $firstElement = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); + $differentElement = $this->driver->findElement(WebDriverBy::cssSelector('#text-simple')); + $againTheFirstElement = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); + + $this->assertTrue($firstElement->equals($againTheFirstElement)); + $this->assertTrue($againTheFirstElement->equals($firstElement)); + + $this->assertFalse($differentElement->equals($firstElement)); + $this->assertFalse($firstElement->equals($differentElement)); + $this->assertFalse($differentElement->equals($againTheFirstElement)); + } } From 9f7019aeeb975d61a7929a73c5809983aac27ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 25 Jan 2017 23:53:49 +0100 Subject: [PATCH 117/600] Improve phpdoc formatting to make apidoc more readable --- lib/Remote/RemoteWebDriver.php | 3 ++- lib/Remote/RemoteWebElement.php | 2 +- lib/Support/XPathEscaper.php | 2 +- lib/WebDriverExpectedCondition.php | 2 +- lib/WebDriverNavigation.php | 2 +- lib/WebDriverOptions.php | 2 +- lib/WebDriverSelect.php | 2 +- lib/WebDriverSelectInterface.php | 16 ++++++++-------- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index a06beb132..ce7450720 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -340,10 +340,11 @@ public function takeScreenshot($save_as = null) * Construct a new WebDriverWait by the current WebDriver instance. * Sample usage: * + * ``` * $driver->wait(20, 1000)->until( * WebDriverExpectedCondition::titleIs('WebDriver Page') * ); - * + * ``` * @param int $timeout_in_second * @param int $interval_in_millisecond * diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 71fdb4305..17fa258c4 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -349,7 +349,7 @@ public function sendKeys($value) * Basically, if you want WebDriver trying to send a file, set the fileDetector * to be LocalFileDetector. Otherwise, keep it UselessFileDetector. * - * eg. $element->setFileDetector(new LocalFileDetector); + * eg. `$element->setFileDetector(new LocalFileDetector);` * * @param FileDetector $detector * @return RemoteWebElement diff --git a/lib/Support/XPathEscaper.php b/lib/Support/XPathEscaper.php index dc5907f01..c90cefa87 100644 --- a/lib/Support/XPathEscaper.php +++ b/lib/Support/XPathEscaper.php @@ -19,7 +19,7 @@ class XPathEscaper { /** * Converts xpath strings with both quotes and ticks into: - * foo'"bar -> concat('foo', "'" ,'"bar') + * `foo'"bar` -> `concat('foo', "'" ,'"bar')` * * @param string $xpathToEscape The xpath to be converted. * @return string The escaped string. diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 58ba939e9..5612a5bbe 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -66,7 +66,7 @@ function (WebDriver $driver) use ($title) { * An expectation for checking substring of a page Title. * * @param string $title The expected substring of Title. - * @return WebDriverExpectedCondition Condition returns whether current page title contains given string. + * @return WebDriverExpectedCondition Condition returns whether current page title contains given string. */ public static function titleContains($title) { diff --git a/lib/WebDriverNavigation.php b/lib/WebDriverNavigation.php index 6c7857d1d..ccc8cee30 100644 --- a/lib/WebDriverNavigation.php +++ b/lib/WebDriverNavigation.php @@ -25,7 +25,7 @@ * Note that they are all blocking functions until the page is loaded by * by default. It could be overridden by 'webdriver.load.strategy' in the * FirefoxProfile preferences. - * https://code.google.com/p/selenium/wiki/DesiredCapabilities#settings + * https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#firefoxprofile-settings */ class WebDriverNavigation { diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index b728382cc..e02d24136 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -37,7 +37,7 @@ public function __construct(ExecuteMethod $executor) /** * Add a specific cookie. * - * Here are the valid attributes of a cookie array. + * Valid attributes of a cookie array: * 'name' : string The name of the cookie; may not be null or an empty string. * 'value' : string The cookie value; may not be null. * 'path' : string OPTIONAL The path the cookie is visible to. Defaults to "/" if omitted. diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index dc6a84038..abe6b54fe 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -21,7 +21,7 @@ use Facebook\WebDriver\Support\XPathEscaper; /** - * Models a default HTML ` tag, providing helper methods to select and deselect options. */ class WebDriverSelect implements WebDriverSelectInterface { diff --git a/lib/WebDriverSelectInterface.php b/lib/WebDriverSelectInterface.php index cec06a33f..bd4db90e4 100644 --- a/lib/WebDriverSelectInterface.php +++ b/lib/WebDriverSelectInterface.php @@ -27,8 +27,8 @@ public function getAllSelectedOptions(); /** * @throws NoSuchElementException * - * @return WebDriverElement The first selected option in this select tag (or - * the currently selected option in a normal select) + * @return WebDriverElement The first selected option in this select tag (or the currently selected option in a + * normal select) */ public function getFirstSelectedOption(); @@ -45,7 +45,7 @@ public function selectByIndex($index); * Select all options that have value attribute matching the argument. That is, when given "foo" this would * select an option like: * - * ; + * `` * * @param string $value The value to match against. * @@ -57,7 +57,7 @@ public function selectByValue($value); * Select all options that display text matching the argument. That is, when given "Bar" this would * select an option like: * - * ; + * `` * * @param string $text The visible text to match against. * @@ -69,7 +69,7 @@ public function selectByVisibleText($text); * Select all options that display text partially matching the argument. That is, when given "Bar" this would * select an option like: * - * ; + * `` * * @param string $text The visible text to match against. * @@ -96,7 +96,7 @@ public function deselectByIndex($index); * Deselect all options that have value attribute matching the argument. That is, when given "foo" this would * deselect an option like: * - * ; + * `` * * @param string $value The value to match against. * @throws UnsupportedOperationException If the SELECT does not support multiple selections @@ -107,7 +107,7 @@ public function deselectByValue($value); * Deselect all options that display text matching the argument. That is, when given "Bar" this would * deselect an option like: * - * ; + * `` * * @param string $text The visible text to match against. * @throws UnsupportedOperationException If the SELECT does not support multiple selections @@ -118,7 +118,7 @@ public function deselectByVisibleText($text); * Deselect all options that display text matching the argument. That is, when given "Bar" this would * deselect an option like: * - * ; + * `` * * @param string $text The visible text to match against. * @throws UnsupportedOperationException If the SELECT does not support multiple selections From 85aa68020ef2cf4fd261b1f1a690052afe67a9e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 26 Jan 2017 00:07:01 +0100 Subject: [PATCH 118/600] Update links to Selenium wiki --- lib/Remote/DesiredCapabilities.php | 4 ++-- lib/Remote/HttpCommandExecutor.php | 3 +-- lib/WebDriverExpectedCondition.php | 2 +- lib/WebDriverOptions.php | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 12060ab7b..94d8e1de2 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -136,7 +136,7 @@ public function isJavascriptEnabled() * @param bool $enabled * @throws Exception * @return DesiredCapabilities - * @see https://code.google.com/p/selenium/wiki/DesiredCapabilities#Read-write_capabilities + * @see https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities */ public function setJavascriptEnabled($enabled) { @@ -144,7 +144,7 @@ public function setJavascriptEnabled($enabled) if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) { throw new Exception( 'isJavascriptEnable() is a htmlunit-only option. ' . - 'See https://code.google.com/p/selenium/wiki/DesiredCapabilities#Read-write_capabilities.' + 'See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities.' ); } diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 2f6c1778f..09bf000d0 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -27,8 +27,7 @@ class HttpCommandExecutor implements WebDriverCommandExecutor { /** - * @see - * http://code.google.com/p/selenium/wiki/JsonWireProtocol#Command_Reference + * @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference */ protected static $commands = [ DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/accept_alert'], diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 5612a5bbe..58ba939e9 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -66,7 +66,7 @@ function (WebDriver $driver) use ($title) { * An expectation for checking substring of a page Title. * * @param string $title The expected substring of Title. - * @return WebDriverExpectedCondition Condition returns whether current page title contains given string. + * @return WebDriverExpectedCondition Condition returns whether current page title contains given string. */ public static function titleContains($title) { diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index e02d24136..14cacd176 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -145,7 +145,7 @@ public function window() * * @param string $log_type The log type. * @return array The list of log entries. - * @see https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Type + * @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#log-type */ public function getLog($log_type) { @@ -159,7 +159,7 @@ public function getLog($log_type) * Get available log types. * * @return array The list of available log types. - * @see https://code.google.com/p/selenium/wiki/JsonWireProtocol#Log_Type + * @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#log-type */ public function getAvailableLogTypes() { From 122ae7abd1b495fcbfe432d75d99f5403ad76e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 27 Jan 2017 19:48:01 +0100 Subject: [PATCH 119/600] Add value object to hold cookie data --- lib/Cookie.php | 208 ++++++++++++++++++++++++++++++++++++++ tests/unit/CookieTest.php | 138 +++++++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 lib/Cookie.php create mode 100644 tests/unit/CookieTest.php diff --git a/lib/Cookie.php b/lib/Cookie.php new file mode 100644 index 000000000..a3b86dbf0 --- /dev/null +++ b/lib/Cookie.php @@ -0,0 +1,208 @@ + null, + 'value' => null, + 'path' => null, + 'domain' => null, + 'expiry' => null, + 'secure' => null, + 'httpOnly' => null, + ]; + + /** + * @param string $name The name of the cookie; may not be null or an empty string. + * @param string $value The cookie value; may not be null. + */ + public function __construct($name, $value) + { + $this->cookie['name'] = $name; + $this->cookie['value'] = $value; + } + + /** + * @param array $cookieArray + * @return Cookie + */ + public static function createFromArray(array $cookieArray) + { + $cookie = new self($cookieArray['name'], $cookieArray['value']); + + if (isset($cookieArray['path'])) { + $cookie->setPath($cookieArray['path']); + } + if (isset($cookieArray['domain'])) { + $cookie->setDomain($cookieArray['domain']); + } + if (isset($cookieArray['expiry'])) { + $cookie->setExpiry($cookieArray['expiry']); + } + if (isset($cookieArray['secure'])) { + $cookie->setSecure($cookieArray['secure']); + } + if (isset($cookieArray['httpOnly'])) { + $cookie->setHttpOnly($cookieArray['httpOnly']); + } + + return $cookie; + } + + /** + * @return string + */ + public function getName() + { + return $this->cookie['name']; + } + + /** + * @return string + */ + public function getValue() + { + return $this->cookie['value']; + } + + /** + * The path the cookie is visible to. Defaults to "/" if omitted. + * + * @param string $path + */ + public function setPath($path) + { + $this->cookie['path'] = $path; + } + + /** + * @return string + */ + public function getPath() + { + return $this->cookie['path']; + } + + /** + * The domain the cookie is visible to. Defaults to the current browsing context's document's URL domain if omitted. + * + * @param string $domain + */ + public function setDomain($domain) + { + $this->cookie['domain'] = $domain; + } + + /** + * @return string + */ + public function getDomain() + { + return $this->cookie['domain']; + } + + /** + * The cookie's expiration date, specified in seconds since Unix Epoch. + * + * @param int $expiry + */ + public function setExpiry($expiry) + { + $this->cookie['expiry'] = (int) $expiry; + } + + /** + * @return int + */ + public function getExpiry() + { + return $this->cookie['expiry']; + } + + /** + * Whether this cookie requires a secure connection (https). Defaults to false if omitted. + * + * @param bool $secure + */ + public function setSecure($secure) + { + $this->cookie['secure'] = $secure; + } + + /** + * @return bool + */ + public function isSecure() + { + return $this->cookie['secure']; + } + + /** + * Whether the cookie is an HTTP only cookie. Defaults to false if omitted. + * + * @param bool $httpOnly + */ + public function setHttpOnly($httpOnly) + { + $this->cookie['httpOnly'] = $httpOnly; + } + + /** + * @return bool + */ + public function isHttpOnly() + { + return $this->cookie['httpOnly']; + } + + /** + * @return array + */ + public function toArray() + { + return $this->cookie; + } + + public function offsetExists($offset) + { + return isset($this->cookie[$offset]); + } + + public function offsetGet($offset) + { + return $this->cookie[$offset]; + } + + public function offsetSet($offset, $value) + { + $this->cookie[$offset] = $value; + } + + public function offsetUnset($offset) + { + unset($this->cookie[$offset]); + } +} diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php new file mode 100644 index 000000000..1ed18b39c --- /dev/null +++ b/tests/unit/CookieTest.php @@ -0,0 +1,138 @@ +setPath('/bar'); + $cookie->setDomain('foo.com'); + $cookie->setExpiry(1485388387); + $cookie->setSecure(true); + $cookie->setHttpOnly(true); + + $this->assertSame('cookieName', $cookie->getName()); + $this->assertSame('someValue', $cookie->getValue()); + $this->assertSame('/bar', $cookie->getPath()); + $this->assertSame('foo.com', $cookie->getDomain()); + $this->assertSame(1485388387, $cookie->getExpiry()); + $this->assertTrue($cookie->isSecure()); + $this->assertTrue($cookie->isHttpOnly()); + + return $cookie; + } + + /** + * @depends testShouldSetAllProperties + * @param Cookie $cookie + */ + public function testShouldBeConvertibleToArray(Cookie $cookie) + { + $this->assertSame( + [ + 'name' => 'cookieName', + 'value' => 'someValue', + 'path' => '/bar', + 'domain' => 'foo.com', + 'expiry' => 1485388387, + 'secure' => true, + 'httpOnly' => true, + ], + $cookie->toArray() + ); + } + + /** + * @depends testShouldSetAllProperties + * @param Cookie $cookie + */ + public function testShouldProvideArrayAccessToProperties(Cookie $cookie) + { + $this->assertSame('cookieName', $cookie['name']); + $this->assertSame('someValue', $cookie['value']); + $this->assertSame('/bar', $cookie['path']); + $this->assertSame('foo.com', $cookie['domain']); + $this->assertSame(1485388387, $cookie['expiry']); + $this->assertTrue($cookie['secure']); + $this->assertTrue($cookie['httpOnly']); + + $cookie->offsetSet('domain', 'bar.com'); + $this->assertSame('bar.com', $cookie['domain']); + $cookie->offsetUnset('domain'); + $this->assertFalse(isset($cookie['domain'])); + } + + public function testShouldBeCreatableFromAnArrayWithBasicValues() + { + $sourceArray = [ + 'name' => 'cookieName', + 'value' => 'someValue', + ]; + + $cookie = Cookie::createFromArray($sourceArray); + + $this->assertSame('cookieName', $cookie['name']); + $this->assertSame('someValue', $cookie['value']); + + $this->assertFalse(isset($cookie['path'])); + $this->assertNull($cookie['path']); + $this->assertNull($cookie->getPath()); + + $this->assertFalse(isset($cookie['domain'])); + $this->assertNull($cookie['domain']); + $this->assertNull($cookie->getDomain()); + + $this->assertFalse(isset($cookie['expiry'])); + $this->assertNull($cookie['expiry']); + $this->assertNull($cookie->getExpiry()); + + $this->assertFalse(isset($cookie['secure'])); + $this->assertNull($cookie['secure']); + $this->assertNull($cookie->isSecure()); + + $this->assertFalse(isset($cookie['httpOnly'])); + $this->assertNull($cookie['httpOnly']); + $this->assertNull($cookie->isHttpOnly()); + } + + public function testShouldBeCreatableFromAnArrayWithAllValues() + { + $sourceArray = [ + 'name' => 'cookieName', + 'value' => 'someValue', + 'path' => '/bar', + 'domain' => 'foo', + 'expiry' => 1485388333, + 'secure' => false, + 'httpOnly' => false, + ]; + + $cookie = Cookie::createFromArray($sourceArray); + + $this->assertSame('cookieName', $cookie['name']); + $this->assertSame('someValue', $cookie['value']); + $this->assertSame('/bar', $cookie['path']); + $this->assertSame('foo', $cookie['domain']); + $this->assertSame(1485388333, $cookie['expiry']); + $this->assertFalse($cookie['secure']); + $this->assertFalse($cookie['httpOnly']); + } +} From 33224c27e3f1fffd4ea62d5c33968496677ac79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 27 Jan 2017 20:15:55 +0100 Subject: [PATCH 120/600] Validate cookie values on creation --- lib/Cookie.php | 33 +++++++++++++++++++++++++++++++ tests/unit/CookieTest.php | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/lib/Cookie.php b/lib/Cookie.php index a3b86dbf0..0434a128b 100644 --- a/lib/Cookie.php +++ b/lib/Cookie.php @@ -15,6 +15,8 @@ namespace Facebook\WebDriver; +use InvalidArgumentException; + /** * Set values of an cookie. * @@ -41,6 +43,9 @@ class Cookie implements \ArrayAccess */ public function __construct($name, $value) { + $this->validateCookieName($name); + $this->validateCookieValue($value); + $this->cookie['name'] = $name; $this->cookie['value'] = $value; } @@ -113,6 +118,10 @@ public function getPath() */ public function setDomain($domain) { + if (mb_strpos($domain, ':') !== false) { + throw new InvalidArgumentException(sprintf('Cookie domain "%s" should not contain a port', $domain)); + } + $this->cookie['domain'] = $domain; } @@ -205,4 +214,28 @@ public function offsetUnset($offset) { unset($this->cookie[$offset]); } + + /** + * @param string $name + */ + protected function validateCookieName($name) + { + if ($name === null || $name === '') { + throw new InvalidArgumentException('Cookie name should be non-empty'); + } + + if (mb_strpos($name, ';') !== false) { + throw new InvalidArgumentException('Cookie name should not contain a ";"'); + } + } + + /** + * @param string $value + */ + protected function validateCookieValue($value) + { + if ($value === null) { + throw new InvalidArgumentException('Cookie value is required when setting a cookie'); + } + } } diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 1ed18b39c..0742a0789 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -135,4 +135,45 @@ public function testShouldBeCreatableFromAnArrayWithAllValues() $this->assertFalse($cookie['secure']); $this->assertFalse($cookie['httpOnly']); } + + /** + * @dataProvider invalidCookieProvider + * @param string $name + * @param string $value + * @param string $domain + * @param string $expectedMessage + */ + public function testShouldValidateCookie($name, $value, $domain, $expectedMessage) + { + if ($expectedMessage) { + $this->setExpectedException(\InvalidArgumentException::class, $expectedMessage); + } + + $cookie = new Cookie($name, $value); + if ($domain !== null) { + $cookie->setDomain($domain); + } + } + + /** + * @return array[] + */ + public function invalidCookieProvider() + { + return [ + // $name, $value, $domain, $expectedMessage + 'name cannot be empty' => ['', 'foo', null, 'Cookie name should be non-empty'], + 'name cannot be null' => [null, 'foo', null, 'Cookie name should be non-empty'], + 'name cannot contain semicolon' => ['name;semicolon', 'foo', null, 'Cookie name should not contain a ";"'], + 'value could be empty string' => ['name', '', null, null], + 'value cannot be null' => ['name', null, null, 'Cookie value is required when setting a cookie'], + 'domain cannot containt port' => [ + 'name', + 'value', + 'localhost:443', + 'Cookie domain "localhost:443" should not contain a port', + ], + 'cookie with valid values' => ['name', 'value', '*.localhost', null], + ]; + } } From 865e9b2c44eb8b1d7f21b4149f319875e5681d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 27 Jan 2017 20:34:00 +0100 Subject: [PATCH 121/600] Add unit test to cookie setting and retrieval in WebDriverOptions class --- tests/unit/WebDriverOptionsTest.php | 152 ++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 tests/unit/WebDriverOptionsTest.php diff --git a/tests/unit/WebDriverOptionsTest.php b/tests/unit/WebDriverOptionsTest.php new file mode 100644 index 000000000..f95671470 --- /dev/null +++ b/tests/unit/WebDriverOptionsTest.php @@ -0,0 +1,152 @@ +executor = $this->getMockBuilder(ExecuteMethod::class) + ->disableOriginalConstructor() + ->getMock(); + } + + public function testShouldAddCookieFromArray() + { + $cookieInArray = [ + 'name' => 'cookieName', + 'value' => 'someValue', + 'path' => '/bar', + 'domain' => 'foo', + 'expiry' => 1485388333, + 'secure' => false, + 'httpOnly' => false, + ]; + + $this->executor->expects($this->once()) + ->method('execute') + ->with(DriverCommand::ADD_COOKIE, ['cookie' => $cookieInArray]); + + $options = new WebDriverOptions($this->executor); + + $options->addCookie($cookieInArray); + } + + public function testShouldGetAllCookies() + { + $this->executor->expects($this->once()) + ->method('execute') + ->with(DriverCommand::GET_ALL_COOKIES) + ->willReturn( + [ + [ + 'path' => '/', + 'domain' => '*.seleniumhq.org', + 'name' => 'firstCookie', + 'httpOnly' => false, + 'secure' => true, + 'value' => 'value', + ], + [ + 'path' => '/', + 'domain' => 'docs.seleniumhq.org', + 'name' => 'secondCookie', + 'httpOnly' => false, + 'secure' => false, + 'value' => 'foo', + ], + ] + ); + + $options = new WebDriverOptions($this->executor); + + $cookies = $options->getCookies(); + + $this->assertCount(2, $cookies); + $this->assertSame('firstCookie', $cookies[0]['name']); + $this->assertSame('secondCookie', $cookies[1]['name']); + } + + public function testShouldGetCookieByName() + { + $this->executor->expects($this->once()) + ->method('execute') + ->with(DriverCommand::GET_ALL_COOKIES) + ->willReturn( + [ + [ + 'path' => '/', + 'domain' => '*.seleniumhq.org', + 'name' => 'cookieToFind', + 'httpOnly' => false, + 'secure' => true, + 'value' => 'value', + ], + [ + 'path' => '/', + 'domain' => 'docs.seleniumhq.org', + 'name' => 'otherCookie', + 'httpOnly' => false, + 'secure' => false, + 'value' => 'foo', + ], + ] + ); + + $options = new WebDriverOptions($this->executor); + + $cookie = $options->getCookieNamed('cookieToFind'); + + $this->assertSame('cookieToFind', $cookie['name']); + $this->assertSame('value', $cookie['value']); + $this->assertSame('/', $cookie['path']); + $this->assertSame('*.seleniumhq.org', $cookie['domain']); + $this->assertFalse($cookie['httpOnly']); + $this->assertTrue($cookie['secure']); + } + + public function testShouldReturnNullIfCookieWithNameNotFound() + { + $this->executor->expects($this->once()) + ->method('execute') + ->with(DriverCommand::GET_ALL_COOKIES) + ->willReturn( + [ + [ + 'path' => '/', + 'domain' => '*.seleniumhq.org', + 'name' => 'cookieToNotFind', + 'httpOnly' => false, + 'secure' => true, + 'value' => 'value', + ], + ] + ); + + $options = new WebDriverOptions($this->executor); + + $this->assertNull($options->getCookieNamed('notExistingCookie')); + } +} From c2e3e30af9d6880f2b07cea0e6b280196aea03ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 27 Jan 2017 20:54:04 +0100 Subject: [PATCH 122/600] Set/receive cookie using Cookie value object instead of an array --- CHANGELOG.md | 3 ++ lib/WebDriverOptions.php | 59 ++++++++++------------------- tests/unit/WebDriverOptionsTest.php | 59 +++++++++++++++++++++++++---- 3 files changed, 75 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04ce2d4dc..1d24e1582 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Changed +- Cookies should now be set using `Cookie` value object instead of an array when passed to to `addCookie()` method of `WebDriverOptions`. +- Cookies retrieved using `getCookieNamed()` and `getCookies()` methods of `WebDriverOptions` are now encapsulated in `Cookie` object instead of an plain array. The object implements `ArrayAccess` interface to provide backward compatibility. ## 1.3.0 - 2017-01-13 ### Added diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index 14cacd176..9791b9f1c 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -37,27 +37,22 @@ public function __construct(ExecuteMethod $executor) /** * Add a specific cookie. * - * Valid attributes of a cookie array: - * 'name' : string The name of the cookie; may not be null or an empty string. - * 'value' : string The cookie value; may not be null. - * 'path' : string OPTIONAL The path the cookie is visible to. Defaults to "/" if omitted. - * 'domain' : string OPTIONAL The domain the cookie is visible to. Defaults to the current browsing context's - * document's URL domain if omitted. - * 'secure' : bool OPTIONAL Whether this cookie requires a secure connection (https). Defaults to false if - * omitted. - * 'httpOnly': bool OPTIONAL Whether the cookie is an HTTP only cookie. Defaults to false if omitted. - * 'expiry' : int OPTIONAL The cookie's expiration date, specified in seconds since Unix Epoch. - * - * @see https://w3c.github.io/webdriver/webdriver-spec.html#cookies - * @param array $cookie An array with key as the attributes mentioned above. + * @see Facebook\WebDriver\Cookie for description of possible cookie properties + * @param Cookie|array $cookie Cookie object. May be also created from array for compatibility reasons. * @return WebDriverOptions The current instance. */ - public function addCookie(array $cookie) + public function addCookie($cookie) { - $this->validateCookie($cookie); + if (is_array($cookie)) { + $cookie = Cookie::createFromArray($cookie); + } + if (!$cookie instanceof Cookie) { + throw new InvalidArgumentException('Cookie must be set from instance of Cookie class or from array.'); + } + $this->executor->execute( DriverCommand::ADD_COOKIE, - ['cookie' => $cookie] + ['cookie' => $cookie->toArray()] ); return $this; @@ -95,7 +90,7 @@ public function deleteCookieNamed($name) * Get the cookie with a given name. * * @param string $name - * @return array The cookie, or null if no cookie with the given name is presented. + * @return Cookie The cookie, or null if no cookie with the given name is presented. */ public function getCookieNamed($name) { @@ -112,11 +107,18 @@ public function getCookieNamed($name) /** * Get all the cookies for the current domain. * - * @return array The array of cookies presented. + * @return Cookie[] The array of cookies presented. */ public function getCookies() { - return $this->executor->execute(DriverCommand::GET_ALL_COOKIES); + $cookieArrays = $this->executor->execute(DriverCommand::GET_ALL_COOKIES); + $cookies = []; + + foreach ($cookieArrays as $cookieArray) { + $cookies[] = Cookie::createFromArray($cookieArray); + } + + return $cookies; } /** @@ -165,23 +167,4 @@ public function getAvailableLogTypes() { return $this->executor->execute(DriverCommand::GET_AVAILABLE_LOG_TYPES); } - - /** - * @param array $cookie - * @throws \InvalidArgumentException - */ - private function validateCookie(array $cookie) - { - if (!isset($cookie['name']) || $cookie['name'] === '' || mb_strpos($cookie['name'], ';') !== false) { - throw new InvalidArgumentException('"name" should be non-empty and does not contain a ";"'); - } - - if (!isset($cookie['value'])) { - throw new InvalidArgumentException('"value" is required when setting a cookie.'); - } - - if (isset($cookie['domain']) && mb_strpos($cookie['domain'], ':') !== false) { - throw new InvalidArgumentException('"domain" should not contain a port:' . (string) $cookie['domain']); - } - } } diff --git a/tests/unit/WebDriverOptionsTest.php b/tests/unit/WebDriverOptionsTest.php index f95671470..38f329726 100644 --- a/tests/unit/WebDriverOptionsTest.php +++ b/tests/unit/WebDriverOptionsTest.php @@ -54,6 +54,47 @@ public function testShouldAddCookieFromArray() $options->addCookie($cookieInArray); } + public function testShouldAddCookieFromCookieObject() + { + $cookieObject = new Cookie('cookieName', 'someValue'); + $cookieObject->setPath('/bar'); + $cookieObject->setDomain('foo'); + $cookieObject->setExpiry(1485388333); + $cookieObject->setSecure(false); + $cookieObject->setHttpOnly(false); + + $expectedCookieData = [ + 'name' => 'cookieName', + 'value' => 'someValue', + 'path' => '/bar', + 'domain' => 'foo', + 'expiry' => 1485388333, + 'secure' => false, + 'httpOnly' => false, + ]; + + $this->executor->expects($this->once()) + ->method('execute') + ->with(DriverCommand::ADD_COOKIE, ['cookie' => $expectedCookieData]); + + $options = new WebDriverOptions($this->executor); + + $options->addCookie($cookieObject); + } + + public function testShouldNotAllowToCreateCookieFromDifferentObjectThanCookie() + { + $notCookie = new \stdClass(); + + $options = new WebDriverOptions($this->executor); + + $this->setExpectedException( + \InvalidArgumentException::class, + 'Cookie must be set from instance of Cookie class or from array.' + ); + $options->addCookie($notCookie); + } + public function testShouldGetAllCookies() { $this->executor->expects($this->once()) @@ -85,8 +126,9 @@ public function testShouldGetAllCookies() $cookies = $options->getCookies(); $this->assertCount(2, $cookies); - $this->assertSame('firstCookie', $cookies[0]['name']); - $this->assertSame('secondCookie', $cookies[1]['name']); + $this->assertContainsOnlyInstancesOf(Cookie::class, $cookies); + $this->assertSame('firstCookie', $cookies[0]->getName()); + $this->assertSame('secondCookie', $cookies[1]->getName()); } public function testShouldGetCookieByName() @@ -119,12 +161,13 @@ public function testShouldGetCookieByName() $cookie = $options->getCookieNamed('cookieToFind'); - $this->assertSame('cookieToFind', $cookie['name']); - $this->assertSame('value', $cookie['value']); - $this->assertSame('/', $cookie['path']); - $this->assertSame('*.seleniumhq.org', $cookie['domain']); - $this->assertFalse($cookie['httpOnly']); - $this->assertTrue($cookie['secure']); + $this->assertInstanceOf(Cookie::class, $cookie); + $this->assertSame('cookieToFind', $cookie->getName()); + $this->assertSame('value', $cookie->getValue()); + $this->assertSame('/', $cookie->getPath()); + $this->assertSame('*.seleniumhq.org', $cookie->getDomain()); + $this->assertFalse($cookie->isHttpOnly()); + $this->assertTrue($cookie->isSecure()); } public function testShouldReturnNullIfCookieWithNameNotFound() From e722283fc5b6d9fe8a420b32eb269a13684af527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 28 Jan 2017 12:45:34 +0100 Subject: [PATCH 123/600] Update example.php to use the Cookie object --- example.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example.php b/example.php index 03b16728e..7bebd10b5 100644 --- a/example.php +++ b/example.php @@ -18,10 +18,10 @@ // adding cookie $driver->manage()->deleteAllCookies(); -$driver->manage()->addCookie([ - 'name' => 'cookie_name', - 'value' => 'cookie_value', -]); + +$cookie = new Cookie('cookie_name', 'cookie_value'); +$driver->manage()->addCookie($cookie); + $cookies = $driver->manage()->getCookies(); print_r($cookies); From 1b303fdbed19c7825a92b8e225c25031f338fdf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 2 Feb 2017 22:37:31 +0100 Subject: [PATCH 124/600] Add functional tests for WebDriverTimeouts --- tests/functional/WebDriverTimeoutsTest.php | 68 ++++++++++++++++++++++ tests/functional/web/delayed_element.html | 19 ++++++ tests/functional/web/index.html | 4 ++ tests/functional/web/slow_loading.html | 14 +++++ tests/functional/web/slow_pixel.png.php | 10 ++++ 5 files changed, 115 insertions(+) create mode 100644 tests/functional/WebDriverTimeoutsTest.php create mode 100644 tests/functional/web/delayed_element.html create mode 100644 tests/functional/web/slow_loading.html create mode 100644 tests/functional/web/slow_pixel.png.php diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php new file mode 100644 index 000000000..b7a7eb183 --- /dev/null +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -0,0 +1,68 @@ +driver->get($this->getTestPath('delayed_element.html')); + + $this->setExpectedException(NoSuchElementException::class); + $this->driver->findElement(WebDriverBy::id('delayed')); + } + + /** + * @covers ::implicitlyWait + */ + public function testShouldGetDelayedElementWithImplicitWait() + { + $this->driver->get($this->getTestPath('delayed_element.html')); + + $this->driver->manage()->timeouts()->implicitlyWait(1); + $element = $this->driver->findElement(WebDriverBy::id('delayed')); + + $this->assertInstanceOf(RemoteWebElement::class, $element); + } + + /** + * @covers ::pageLoadTimeout + */ + public function testShouldFailIfPageIsLoadingLongerThanPageLoadTimeout() + { + if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $this->driver->manage()->timeouts()->pageLoadTimeout(1); + + try { + $this->driver->get($this->getTestPageUrl('slow_loading.html')); + $this->fail('ScriptTimeoutException or TimeOutException exception should be thrown'); + } catch (TimeOutException $e) { // thrown by Selenium 3.0.0+ + } catch (ScriptTimeoutException $e) { // thrown by Selenium 2 + } + } +} diff --git a/tests/functional/web/delayed_element.html b/tests/functional/web/delayed_element.html new file mode 100644 index 000000000..b0f057a9a --- /dev/null +++ b/tests/functional/web/delayed_element.html @@ -0,0 +1,19 @@ + + + + + php-webdriver test page with delayed element appearing + + + +

    + + + + + diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index f0dc03af4..c3d53c4a3 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -12,6 +12,10 @@

    Welcome to the facebook/php-webdriver testing page.

    Form with file upload | New window opener test page + | + Delayed render + | + Slow loading page

    Test by ID

    Test by Class

    diff --git a/tests/functional/web/slow_loading.html b/tests/functional/web/slow_loading.html new file mode 100644 index 000000000..984272bf3 --- /dev/null +++ b/tests/functional/web/slow_loading.html @@ -0,0 +1,14 @@ + + + + + php-webdriver test page which is taking long to load + + + +

    This page is loading slowly

    + +Slowly loading pixel + + + diff --git a/tests/functional/web/slow_pixel.png.php b/tests/functional/web/slow_pixel.png.php new file mode 100644 index 000000000..d95805e21 --- /dev/null +++ b/tests/functional/web/slow_pixel.png.php @@ -0,0 +1,10 @@ + Date: Fri, 3 Feb 2017 01:08:44 +0100 Subject: [PATCH 125/600] Minor phpdoc formatting fixes --- lib/Remote/RemoteWebDriver.php | 14 ++++++-------- lib/WebDriverTimeouts.php | 9 +++------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index ce7450720..ed69c23ac 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -274,9 +274,8 @@ public function quit() } /** - * Inject a snippet of JavaScript into the page for execution in the context - * of the currently selected frame. The executed script is assumed to be - * synchronous and the result of evaluating the script will be returned. + * Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. + * The executed script is assumed to be synchronous and the result of evaluating the script will be returned. * * @param string $script The script to inject. * @param array $arguments The arguments of the script. @@ -293,13 +292,12 @@ public function executeScript($script, array $arguments = []) } /** - * Inject a snippet of JavaScript into the page for asynchronous execution in - * the context of the currently selected frame. + * Inject a snippet of JavaScript into the page for asynchronous execution in the context of the currently selected + * frame. * - * The driver will pass a callback as the last argument to the snippet, and - * block until the callback is invoked. + * The driver will pass a callback as the last argument to the snippet, and block until the callback is invoked. * - * @see WebDriverExecuteAsyncScriptTestCase + * You may need to define script timeout using `setScriptTimeout()` method of `WebDriverTimeouts` first. * * @param string $script The script to inject. * @param array $arguments The arguments of the script. diff --git a/lib/WebDriverTimeouts.php b/lib/WebDriverTimeouts.php index d62f2a124..6903f7080 100644 --- a/lib/WebDriverTimeouts.php +++ b/lib/WebDriverTimeouts.php @@ -34,8 +34,7 @@ public function __construct(ExecuteMethod $executor) } /** - * Specify the amount of time the driver should wait when searching for an - * element if it is not immediately present. + * Specify the amount of time the driver should wait when searching for an element if it is not immediately present. * * @param int $seconds Wait time in second. * @return WebDriverTimeouts The current instance. @@ -51,8 +50,7 @@ public function implicitlyWait($seconds) } /** - * Set the amount of time to wait for an asynchronous script to finish - * execution before throwing an error. + * Set the amount of time to wait for an asynchronous script to finish execution before throwing an error. * * @param int $seconds Wait time in second. * @return WebDriverTimeouts The current instance. @@ -68,8 +66,7 @@ public function setScriptTimeout($seconds) } /** - * Set the amount of time to wait for a page load to complete before throwing - * an error. + * Set the amount of time to wait for a page load to complete before throwing an error. * * @param int $seconds Wait time in second. * @return WebDriverTimeouts The current instance. From 91b92332630c24556b608d7c9b31274d9bd36358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 3 Feb 2017 01:12:28 +0100 Subject: [PATCH 126/600] Add some more unit tests for WebDriverOptions --- tests/unit/WebDriverOptionsTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/unit/WebDriverOptionsTest.php b/tests/unit/WebDriverOptionsTest.php index 38f329726..5e335854f 100644 --- a/tests/unit/WebDriverOptionsTest.php +++ b/tests/unit/WebDriverOptionsTest.php @@ -192,4 +192,20 @@ public function testShouldReturnNullIfCookieWithNameNotFound() $this->assertNull($options->getCookieNamed('notExistingCookie')); } + + public function testShouldReturnTimeoutsInstance() + { + $options = new WebDriverOptions($this->executor); + + $timeouts = $options->timeouts(); + $this->assertInstanceOf(WebDriverTimeouts::class, $timeouts); + } + + public function testShouldReturnWindowInstance() + { + $options = new WebDriverOptions($this->executor); + + $window = $options->window(); + $this->assertInstanceOf(WebDriverWindow::class, $window); + } } From 7a6bf0dd9c785e11660c798e3d895d83babf2306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 7 Feb 2017 23:45:13 +0100 Subject: [PATCH 127/600] Fix incorrect covers annotation --- tests/functional/RemoteWebDriverTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 918b3514b..847479afa 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -131,7 +131,7 @@ public function testShouldGetWindowHandles() } /** - * @covers ::getWindowHandles + * @covers ::close */ public function testShouldCloseWindow() { From 2a7a3537450331d9c6a7f6f9e06587858a8ce903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 7 Feb 2017 23:52:33 +0100 Subject: [PATCH 128/600] Add missing phpdoc --- lib/Remote/RemoteWebDriver.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index ed69c23ac..58381cff4 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -59,6 +59,11 @@ class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInpu */ protected $executeMethod; + /** + * @param HttpCommandExecutor $commandExecutor + * @param string $sessionId + * @param WebDriverCapabilities|null $capabilities + */ protected function __construct( HttpCommandExecutor $commandExecutor, $sessionId, From ca4300c0be26750dd94eb4694f9ca78ee96cf8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 7 Feb 2017 23:57:58 +0100 Subject: [PATCH 129/600] Add unit tests for parts of RemoteWebDriver which do not interact with the real remote --- tests/unit/Remote/HttpCommandExecutorTest.php | 1 + tests/unit/Remote/RemoteWebDriverTest.php | 117 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 tests/unit/Remote/RemoteWebDriverTest.php diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php index 268b3e873..63d004e6b 100644 --- a/tests/unit/Remote/HttpCommandExecutorTest.php +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -20,6 +20,7 @@ class HttpCommandExecutorTest extends \PHPUnit_Framework_TestCase { use PHPMock; + /** @var HttpCommandExecutor */ private $executor; diff --git a/tests/unit/Remote/RemoteWebDriverTest.php b/tests/unit/Remote/RemoteWebDriverTest.php new file mode 100644 index 000000000..48b149f84 --- /dev/null +++ b/tests/unit/Remote/RemoteWebDriverTest.php @@ -0,0 +1,117 @@ +driver = RemoteWebDriver::createBySessionID('session-id', 'http://foo.bar:4444/'); + } + + /** + * @covers ::manage + */ + public function testShouldCreateWebDriverOptionsInstance() + { + $wait = $this->driver->manage(); + + $this->assertInstanceOf(WebDriverOptions::class, $wait); + } + + /** + * @covers ::navigate + */ + public function testShouldCreateWebDriverNavigationInstance() + { + $wait = $this->driver->navigate(); + + $this->assertInstanceOf(WebDriverNavigation::class, $wait); + } + + /** + * @covers ::switchTo + */ + public function testShouldCreateRemoteTargetLocatorInstance() + { + $wait = $this->driver->switchTo(); + + $this->assertInstanceOf(RemoteTargetLocator::class, $wait); + } + + /** + * @covers ::getMouse + */ + public function testShouldCreateRemoteMouseInstance() + { + $wait = $this->driver->getMouse(); + + $this->assertInstanceOf(RemoteMouse::class, $wait); + } + + /** + * @covers ::getKeyboard + */ + public function testShouldCreateRemoteKeyboardInstance() + { + $wait = $this->driver->getKeyboard(); + + $this->assertInstanceOf(RemoteKeyboard::class, $wait); + } + + /** + * @covers ::getTouch + */ + public function testShouldCreateRemoteTouchScreenInstance() + { + $wait = $this->driver->getTouch(); + + $this->assertInstanceOf(RemoteTouchScreen::class, $wait); + } + + /** + * @covers ::action + */ + public function testShouldCreateWebDriverActionsInstance() + { + $wait = $this->driver->action(); + + $this->assertInstanceOf(WebDriverActions::class, $wait); + } + + /** + * @covers ::wait + */ + public function testShouldCreateWebDriverWaitInstance() + { + $wait = $this->driver->wait(15, 1337); + + $this->assertInstanceOf(WebDriverWait::class, $wait); + } +} From 4eb204b350c4647775b0137908a62a9f3b912c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Feb 2017 00:51:28 +0100 Subject: [PATCH 130/600] Test reusing WebDriver session ID --- lib/Remote/RemoteWebDriver.php | 2 +- tests/functional/RemoteWebDriverCreateTest.php | 17 +++++++++++++++++ tests/functional/WebDriverTestCase.php | 1 - 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 58381cff4..f8b8e5e6e 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -135,7 +135,7 @@ public static function create( * [Experimental] Construct the RemoteWebDriver by an existing session. * * This constructor can boost the performance a lot by reusing the same browser for the whole test suite. - * You cannot the desired capabilities because the session was created before. + * You cannot pass the desired capabilities because the session was created before. * * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param string $session_id The existing session id diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 4f05a4319..161adb2bf 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -60,4 +60,21 @@ public function testShouldCreateWebDriverWithRequiredCapabilities() $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); } + + public function testShouldCreateInstanceFromExistingSessionId() + { + // Create driver instance and load page "index.html" + $originalDriver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities); + $originalDriver->get($this->getTestPath('index.html')); + $this->assertContains('/index.html', $originalDriver->getCurrentURL()); + + // Store session ID + $sessionId = $originalDriver->getSessionID(); + + // Create new RemoteWebDriver instance based on the session ID + $this->driver = RemoteWebDriver::createBySessionID($sessionId); + + // Check we reused the previous instance (window) and it has the same URL + $this->assertContains('/index.html', $this->driver->getCurrentURL()); + } } diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 8c2fd4b8d..5626d1e82 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -29,7 +29,6 @@ class WebDriverTestCase extends \PHPUnit_Framework_TestCase protected $createWebDriver = true; /** @var string */ protected $serverUrl = 'http://localhost:4444/wd/hub'; - /** @var RemoteWebDriver $driver */ protected $driver; /** @var DesiredCapabilities */ From 67cb575fc727530d6c4cb4a852dd34b45f036074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Feb 2017 01:04:42 +0100 Subject: [PATCH 131/600] Add new php-cs-fixer rule --- .php_cs.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/.php_cs.dist b/.php_cs.dist index c40510179..d95f9d0fc 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -71,6 +71,7 @@ return PhpCsFixer\Config::create() 'trailing_comma_in_multiline_array' => true, 'trim_array_spaces' => true, 'unary_operator_spaces' => true, + 'visibility_required' => true, 'whitespace_after_comma_in_array' => true, ]) ->setRiskyAllowed(true) From 7cd8e163883a6dd22f0c5f6372fba05e5b8d2785 Mon Sep 17 00:00:00 2001 From: Nino Date: Wed, 8 Feb 2017 13:09:02 +0100 Subject: [PATCH 132/600] Added ext-zip to require section of composer.json (#410) * Added ext-zip to require section of composer.json, as it is required by file upload and firefox profile. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9114afdd8..3523361f9 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "require": { "php": "^5.5 || ~7.0", "symfony/process": "^2.8 || ^3.1", - "ext-curl": "*" + "ext-curl": "*", + "ext-zip": "*" }, "require-dev": { "phpunit/phpunit": "4.6.* || ~5.0", From 7b5d48850ad5f8085363c839fc2d250a7af62732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Feb 2017 14:30:47 +0100 Subject: [PATCH 133/600] Mark executeSQL command deprecated - as it was removed from officialn java bindings in 2014 --- lib/Remote/DriverCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index e2ce958b5..1b86c71c6 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -83,6 +83,7 @@ class DriverCommand const SET_TIMEOUT = 'setTimeout'; const IMPLICITLY_WAIT = 'implicitlyWait'; const SET_SCRIPT_TIMEOUT = 'setScriptTimeout'; + /** @deprecated */ const EXECUTE_SQL = 'executeSQL'; const GET_LOCATION = 'getLocation'; const SET_LOCATION = 'setLocation'; @@ -91,18 +92,21 @@ class DriverCommand const CLEAR_APP_CACHE = 'clearAppCache'; const IS_BROWSER_ONLINE = 'isBrowserOnline'; const SET_BROWSER_ONLINE = 'setBrowserOnline'; + // Local storage const GET_LOCAL_STORAGE_ITEM = 'getLocalStorageItem'; const GET_LOCAL_STORAGE_KEYS = 'getLocalStorageKeys'; const SET_LOCAL_STORAGE_ITEM = 'setLocalStorageItem'; const REMOVE_LOCAL_STORAGE_ITEM = 'removeLocalStorageItem'; const CLEAR_LOCAL_STORAGE = 'clearLocalStorage'; const GET_LOCAL_STORAGE_SIZE = 'getLocalStorageSize'; + // Session storage const GET_SESSION_STORAGE_ITEM = 'getSessionStorageItem'; const GET_SESSION_STORAGE_KEYS = 'getSessionStorageKey'; const SET_SESSION_STORAGE_ITEM = 'setSessionStorageItem'; const REMOVE_SESSION_STORAGE_ITEM = 'removeSessionStorageItem'; const CLEAR_SESSION_STORAGE = 'clearSessionStorage'; const GET_SESSION_STORAGE_SIZE = 'getSessionStorageSize'; + // Screen orientation const SET_SCREEN_ORIENTATION = 'setScreenOrientation'; const GET_SCREEN_ORIENTATION = 'getScreenOrientation'; // These belong to the Advanced user interactions - an element is optional for these commands. From 58a942c1091939e02eb6aa2f56c0ebb2d2c9aaa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Feb 2017 20:49:38 +0100 Subject: [PATCH 134/600] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d24e1582..6b99a4f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Changed - Cookies should now be set using `Cookie` value object instead of an array when passed to to `addCookie()` method of `WebDriverOptions`. - Cookies retrieved using `getCookieNamed()` and `getCookies()` methods of `WebDriverOptions` are now encapsulated in `Cookie` object instead of an plain array. The object implements `ArrayAccess` interface to provide backward compatibility. +- `ext-zip` is now specified as required dependency in composer.json (but the extension was already required by the code, though). ## 1.3.0 - 2017-01-13 ### Added From 47191c71d0024d1158326a5178dc931a1915ebd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Feb 2017 01:53:36 +0100 Subject: [PATCH 135/600] Add WebDriverAlert functional test --- tests/functional/WebDriverAlertTest.php | 103 ++++++++++++++++++++++++ tests/functional/web/alert.html | 35 ++++++++ tests/functional/web/index.html | 2 + 3 files changed, 140 insertions(+) create mode 100644 tests/functional/WebDriverAlertTest.php create mode 100644 tests/functional/web/alert.html diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php new file mode 100644 index 000000000..ce403c549 --- /dev/null +++ b/tests/functional/WebDriverAlertTest.php @@ -0,0 +1,103 @@ +driver->get($this->getTestPath('alert.html')); + } + + public function testShouldAcceptAlert() + { + // Open alert + $this->driver->findElement(WebDriverBy::id('open-alert'))->click(); + + // Wait until present + $this->driver->wait()->until(WebDriverExpectedCondition::alertIsPresent()); + + $this->assertSame('This is alert', $this->driver->switchTo()->alert()->getText()); + + $this->driver->switchTo()->alert()->accept(); + + $this->setExpectedException(NoAlertOpenException::class); + $this->driver->switchTo()->alert()->accept(); + } + + public function testShouldAcceptAndDismissConfirmation() + { + if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + /** @see https://github.com/SeleniumHQ/htmlunit-driver/issues/14 */ + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + // Open confirmation + $this->driver->findElement(WebDriverBy::id('open-confirm'))->click(); + + // Wait until present + $this->driver->wait()->until(WebDriverExpectedCondition::alertIsPresent()); + + $this->assertSame('Do you confirm?', $this->driver->switchTo()->alert()->getText()); + + // Test accepting + $this->driver->switchTo()->alert()->accept(); + $this->assertSame('accepted', $this->getResultText()); + + // Open confirmation + $this->driver->findElement(WebDriverBy::id('open-confirm'))->click(); + + // Test dismissal + $this->driver->switchTo()->alert()->dismiss(); + $this->assertSame('dismissed', $this->getResultText()); + } + + public function testShouldSubmitPromptText() + { + if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + /** @see https://github.com/SeleniumHQ/htmlunit-driver/issues/14 */ + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + // Open confirmation + $this->driver->findElement(WebDriverBy::id('open-prompt'))->click(); + + // Wait until present + $this->driver->wait()->until(WebDriverExpectedCondition::alertIsPresent()); + + $this->assertSame('Enter prompt value', $this->driver->switchTo()->alert()->getText()); + + $this->driver->switchTo()->alert()->sendKeys('Text entered to prompt'); + $this->driver->switchTo()->alert()->accept(); + + $this->assertSame('Text entered to prompt', $this->getResultText()); + } + + private function getResultText() + { + return $this->driver + ->findElement(WebDriverBy::id('result')) + ->getText(); + } +} diff --git a/tests/functional/web/alert.html b/tests/functional/web/alert.html new file mode 100644 index 000000000..079d75130 --- /dev/null +++ b/tests/functional/web/alert.html @@ -0,0 +1,35 @@ + + + + + Open an alert + + + +

    + Open alert +
    + + Open confirm +
    + + Open prompt +
    +

    + +
    + + + + + diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index c3d53c4a3..8e314f798 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -16,6 +16,8 @@

    Welcome to the facebook/php-webdriver testing page.

    Delayed render | Slow loading page + | + Javascript alerts

    Test by ID

    Test by Class

    From ff3c556707cb1524ad99d4752db496ab574bf41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 10 Feb 2017 15:02:01 +0100 Subject: [PATCH 136/600] Prepare toArray() method to be added to WebDriverCapabilities interface in next major version --- lib/WebDriver.php | 2 +- lib/WebDriverCapabilities.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/WebDriver.php b/lib/WebDriver.php index ea413f883..f6e8200ae 100755 --- a/lib/WebDriver.php +++ b/lib/WebDriver.php @@ -128,9 +128,9 @@ public function navigate(); */ public function switchTo(); + // TODO: Add in next major release (BC) ///** // * @return WebDriverTouchScreen - // * @todo Add in next major release (BC) // */ //public function getTouch(); diff --git a/lib/WebDriverCapabilities.php b/lib/WebDriverCapabilities.php index 6fce03c08..b489a1e6e 100644 --- a/lib/WebDriverCapabilities.php +++ b/lib/WebDriverCapabilities.php @@ -48,4 +48,10 @@ public function is($capability_name); * @return bool Whether javascript is enabled. */ public function isJavascriptEnabled(); + + // TODO: Add in next major release (BC) + ///** + // * @return array + // */ + //public function toArray(); } From 85f8ac1e4705f92ea2b4d2abe4f164c36cce6809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 18 Dec 2016 01:27:57 +0100 Subject: [PATCH 137/600] Run tests on SauceLabs --- .travis.yml | 18 ++++++- tests/functional/FileUploadTest.php | 2 +- .../functional/RemoteWebDriverCreateTest.php | 6 +-- .../RemoteWebDriverFindElementTest.php | 8 +-- tests/functional/RemoteWebDriverTest.php | 28 ++++++----- tests/functional/RemoteWebElementTest.php | 24 ++++----- tests/functional/WebDriverAlertTest.php | 2 +- tests/functional/WebDriverByTest.php | 2 +- tests/functional/WebDriverSelectTest.php | 2 +- tests/functional/WebDriverTestCase.php | 50 +++++++++++++------ tests/functional/WebDriverTimeoutsTest.php | 4 +- 11 files changed, 93 insertions(+), 53 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7c0cd3e77..f7229a2c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,25 @@ php: matrix: include: - # Add build to run tests against Firefox (other runs are agains HtmlUnit by default) + # Add build to run tests against Firefox inside Travis environment (other runs are agains HtmlUnit by default) - php: 7.0 env: BROWSER_NAME="firefox" + # Build with lowest possible dependencies - php: 7.0 env: dependencies="--prefer-lowest" + + # Saucelabs builds + - php: 7.0 + env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" + before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - php: 7.0 + env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="45.0" PLATFORM="Linux" + before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - php: 7.0 + env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" + before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + # Add PHP 7 build to check codestyle only in PHP 7 build - php: 7.0 env: CHECK_CODESTYLE=1 @@ -66,3 +79,6 @@ addons: apt: packages: - oracle-java8-installer + sauce_connect: true + jwt: + secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index e8878e642..ef6cf1bb2 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -52,7 +52,7 @@ public function testShouldUploadAFile() public function xtestUselessFileDetectorSendKeys() { - $this->driver->get($this->getTestPath('upload.html')); + $this->driver->get($this->getTestPageUrl('upload.html')); $file_input = $this->driver->findElement(WebDriverBy::id('upload')); $file_input->sendKeys($this->getTestFilePath()); diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 161adb2bf..95ff4851c 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -34,7 +34,7 @@ public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); - $this->assertSame($this->serverUrl, $this->driver->getCommandExecutor()->getAddressOfRemoteServer()); + $this->assertNotEmpty($this->driver->getCommandExecutor()->getAddressOfRemoteServer()); $this->assertInternalType('string', $this->driver->getSessionID()); $this->assertNotEmpty($this->driver->getSessionID()); @@ -65,14 +65,14 @@ public function testShouldCreateInstanceFromExistingSessionId() { // Create driver instance and load page "index.html" $originalDriver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities); - $originalDriver->get($this->getTestPath('index.html')); + $originalDriver->get($this->getTestPageUrl('index.html')); $this->assertContains('/index.html', $originalDriver->getCurrentURL()); // Store session ID $sessionId = $originalDriver->getSessionID(); // Create new RemoteWebDriver instance based on the session ID - $this->driver = RemoteWebDriver::createBySessionID($sessionId); + $this->driver = RemoteWebDriver::createBySessionID($sessionId, $this->serverUrl); // Check we reused the previous instance (window) and it has the same URL $this->assertContains('/index.html', $this->driver->getCurrentURL()); diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index ad1daf348..808763bad 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -26,7 +26,7 @@ class RemoteWebDriverFindElementTest extends WebDriverTestCase { public function testShouldThrowExceptionOfElementCannotBeFound() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $this->setExpectedException(NoSuchElementException::class, 'Unable to locate element'); $this->driver->findElement(WebDriverBy::id('not_existing')); @@ -34,7 +34,7 @@ public function testShouldThrowExceptionOfElementCannotBeFound() public function testShouldFindElementIfExistsOnAPage() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $element = $this->driver->findElement(WebDriverBy::id('id_test')); @@ -43,7 +43,7 @@ public function testShouldFindElementIfExistsOnAPage() public function testShouldReturnEmptyArrayIfElementsCannotBeFound() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $elements = $this->driver->findElements(WebDriverBy::cssSelector('not_existing')); @@ -53,7 +53,7 @@ public function testShouldReturnEmptyArrayIfElementsCannotBeFound() public function testShouldFindMultipleElements() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $elements = $this->driver->findElements(WebDriverBy::cssSelector('ul > li')); diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 847479afa..0f38d0f3c 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -29,7 +29,7 @@ class RemoteWebDriverTest extends WebDriverTestCase */ public function testShouldGetPageTitle() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $this->assertEquals( 'php-webdriver test page', @@ -43,7 +43,7 @@ public function testShouldGetPageTitle() */ public function testShouldGetCurrentUrl() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $this->assertContains( '/index.html', @@ -56,7 +56,7 @@ public function testShouldGetCurrentUrl() */ public function testShouldGetPageSource() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $source = $this->driver->getPageSource(); $this->assertContains('

    ', $source); @@ -79,7 +79,9 @@ public function testShouldGetSessionId() */ public function testShouldGetAllSessions() { - $sessions = RemoteWebDriver::getAllSessions(); + $this->skipOnSauceLabs('getAllSessions() is not supported on SauceLabs'); + + $sessions = RemoteWebDriver::getAllSessions($this->serverUrl); $this->assertInternalType('array', $sessions); $this->assertCount(1, $sessions); @@ -96,12 +98,14 @@ public function testShouldGetAllSessions() */ public function testShouldQuitAndUnsetExecutor() { - $this->assertCount(1, RemoteWebDriver::getAllSessions()); + $this->skipOnSauceLabs('getAllSessions() is not supported on SauceLabs'); + + $this->assertCount(1, RemoteWebDriver::getAllSessions($this->serverUrl)); $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); $this->driver->quit(); - $this->assertCount(0, RemoteWebDriver::getAllSessions()); + $this->assertCount(0, RemoteWebDriver::getAllSessions($this->serverUrl)); $this->assertNull($this->driver->getCommandExecutor()); } @@ -111,7 +115,7 @@ public function testShouldQuitAndUnsetExecutor() */ public function testShouldGetWindowHandles() { - $this->driver->get($this->getTestPath('open_new_window.html')); + $this->driver->get($this->getTestPageUrl('open_new_window.html')); $windowHandle = $this->driver->getWindowHandle(); $windowHandles = $this->driver->getWindowHandles(); @@ -135,7 +139,7 @@ public function testShouldGetWindowHandles() */ public function testShouldCloseWindow() { - $this->driver->get($this->getTestPath('open_new_window.html')); + $this->driver->get($this->getTestPageUrl('open_new_window.html')); $this->driver->findElement(WebDriverBy::cssSelector('a'))->click(); $this->assertCount(2, $this->driver->getWindowHandles()); @@ -150,7 +154,7 @@ public function testShouldCloseWindow() */ public function testShouldExecuteScriptAndDoNotBlockExecution() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $element = $this->driver->findElement(WebDriverBy::id('id_test')); $this->assertSame('Test by ID', $element->getText()); @@ -176,7 +180,7 @@ public function testShouldExecuteAsyncScriptAndWaitUntilItIsFinished() { $this->driver->manage()->timeouts()->setScriptTimeout(1); - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $element = $this->driver->findElement(WebDriverBy::id('id_test')); $this->assertSame('Test by ID', $element->getText()); @@ -209,7 +213,7 @@ public function testShouldTakeScreenshot() $this->markTestSkipped('Screenshots are not supported by HtmlUnit browser'); } - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $outputPng = $this->driver->takeScreenshot(); @@ -234,7 +238,7 @@ public function testShouldSaveScreenshotToFile() $screenshotPath = sys_get_temp_dir() . '/selenium-screenshot.png'; - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $this->driver->takeScreenshot($screenshotPath); diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index e5d1ead06..26d13f6e2 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -25,7 +25,7 @@ class RemoteWebElementTest extends WebDriverTestCase */ public function testShouldGetText() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $elementWithSimpleText = $this->driver->findElement(WebDriverBy::id('text-simple')); $elementWithTextWithSpaces = $this->driver->findElement(WebDriverBy::id('text-with-spaces')); @@ -38,7 +38,7 @@ public function testShouldGetText() */ public function testShouldGetAttributeValue() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $element = $this->driver->findElement(WebDriverBy::id('text-simple')); @@ -52,7 +52,7 @@ public function testShouldGetAttributeValue() */ public function testShouldGetLocation() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $element = $this->driver->findElement(WebDriverBy::id('element-with-location')); @@ -67,7 +67,7 @@ public function testShouldGetLocation() */ public function testShouldGetSize() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $element = $this->driver->findElement(WebDriverBy::id('element-with-location')); @@ -82,7 +82,7 @@ public function testShouldGetSize() */ public function testShouldGetCssValue() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $elementWithBorder = $this->driver->findElement(WebDriverBy::id('text-simple')); $elementWithoutBorder = $this->driver->findElement(WebDriverBy::id('text-with-spaces')); @@ -99,7 +99,7 @@ public function testShouldGetCssValue() */ public function testShouldGetTagName() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $paragraphElement = $this->driver->findElement(WebDriverBy::id('id_test')); @@ -111,7 +111,7 @@ public function testShouldGetTagName() */ public function testShouldClick() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $linkElement = $this->driver->findElement(WebDriverBy::id('a-form')); $linkElement->click(); @@ -126,7 +126,7 @@ public function testShouldClick() */ public function testShouldClearFormElementText() { - $this->driver->get($this->getTestPath('form.html')); + $this->driver->get($this->getTestPageUrl('form.html')); $input = $this->driver->findElement(WebDriverBy::id('input-text')); $textarea = $this->driver->findElement(WebDriverBy::id('textarea')); @@ -145,7 +145,7 @@ public function testShouldClearFormElementText() */ public function testShouldSendKeysToFormElement() { - $this->driver->get($this->getTestPath('form.html')); + $this->driver->get($this->getTestPageUrl('form.html')); $input = $this->driver->findElement(WebDriverBy::id('input-text')); $textarea = $this->driver->findElement(WebDriverBy::id('textarea')); @@ -168,7 +168,7 @@ public function testShouldSendKeysToFormElement() */ public function testShouldDetectEnabledInputs() { - $this->driver->get($this->getTestPath('form.html')); + $this->driver->get($this->getTestPageUrl('form.html')); $inputEnabled = $this->driver->findElement(WebDriverBy::id('input-text')); $inputDisabled = $this->driver->findElement(WebDriverBy::id('input-text-disabled')); @@ -182,7 +182,7 @@ public function testShouldDetectEnabledInputs() */ public function testShouldSelectedInputsOrOptions() { - $this->driver->get($this->getTestPath('form.html')); + $this->driver->get($this->getTestPageUrl('form.html')); $checkboxSelected = $this->driver->findElement( WebDriverBy::cssSelector('input[name=checkbox][value=second]') @@ -263,7 +263,7 @@ public function testShouldSubmitFormByClickOnSubmitInput() */ public function testShouldCompareEqualsElement() { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $firstElement = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); $differentElement = $this->driver->findElement(WebDriverBy::cssSelector('#text-simple')); diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index ce403c549..eddf3a9ae 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -27,7 +27,7 @@ protected function setUp() { parent::setUp(); - $this->driver->get($this->getTestPath('alert.html')); + $this->driver->get($this->getTestPageUrl('alert.html')); } public function testShouldAcceptAlert() diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php index 753790248..43d8c0457 100644 --- a/tests/functional/WebDriverByTest.php +++ b/tests/functional/WebDriverByTest.php @@ -36,7 +36,7 @@ public function testShouldFindTextElementByLocator( $expectedText = null, $expectedAttributeValue = null ) { - $this->driver->get($this->getTestPath('index.html')); + $this->driver->get($this->getTestPageUrl('index.html')); $by = call_user_func([WebDriverBy::class, $webDriverByLocatorMethod], $webDriverByLocatorValue); $element = $this->driver->findElement($by); diff --git a/tests/functional/WebDriverSelectTest.php b/tests/functional/WebDriverSelectTest.php index 3a7d55f24..ac32cbca7 100644 --- a/tests/functional/WebDriverSelectTest.php +++ b/tests/functional/WebDriverSelectTest.php @@ -29,7 +29,7 @@ protected function setUp() { parent::setUp(); - $this->driver->get($this->getTestPath('form.html')); + $this->driver->get($this->getTestPageUrl('form.html')); } public function testShouldCreateNewInstanceForSelectElementAndDetectIfItIsMultiple() diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 5626d1e82..62f98b5d1 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -38,13 +38,17 @@ protected function setUp() { $this->desiredCapabilities = new DesiredCapabilities(); - if (getenv('BROWSER_NAME')) { - $browserName = getenv('BROWSER_NAME'); + if (getenv('SAUCELABS')) { + $this->setUpSauceLabs(); } else { - $browserName = WebDriverBrowserType::HTMLUNIT; - } + if (getenv('BROWSER_NAME')) { + $browserName = getenv('BROWSER_NAME'); + } else { + $browserName = WebDriverBrowserType::HTMLUNIT; + } - $this->desiredCapabilities->setBrowserName($browserName); + $this->desiredCapabilities->setBrowserName($browserName); + } if ($this->createWebDriver) { $this->driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities); @@ -63,24 +67,40 @@ protected function tearDown() } /** - * Get the URL of the test html on filesystem. + * Get the URL of given test HTML on running webserver. * - * @param $path + * @param string $path * @return string */ - protected function getTestPath($path) + protected function getTestPageUrl($path) { - return 'file:///' . __DIR__ . '/web/' . $path; + return 'http://localhost:8000/' . $path; + } + + protected function setUpSauceLabs() + { + $this->serverUrl = sprintf( + 'http://%s:%s@ondemand.saucelabs.com/wd/hub', + getenv('SAUCE_USERNAME'), + getenv('SAUCE_ACCESS_KEY') + ); + $this->desiredCapabilities->setBrowserName(getenv('BROWSER_NAME')); + $this->desiredCapabilities->setVersion(getenv('VERSION')); + $this->desiredCapabilities->setPlatform(getenv('PLATFORM')); + + if (getenv('TRAVIS_JOB_NUMBER')) { + $this->desiredCapabilities->setCapability('tunnel-identifier', getenv('TRAVIS_JOB_NUMBER')); + $this->desiredCapabilities->setCapability('build', getenv('TRAVIS_JOB_NUMBER')); + } } /** - * Get the URL of given test HTML on running webserver. - * - * @param string $path - * @return string + * @param string $message */ - protected function getTestPageUrl($path) + protected function skipOnSauceLabs($message = 'Not supported by SauceLabs') { - return 'http://localhost:8000/' . $path; + if (getenv('SAUCELABS')) { + $this->markTestSkipped($message); + } } } diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index b7a7eb183..51be6e13a 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -28,7 +28,7 @@ class WebDriverTimeoutsTest extends WebDriverTestCase { public function testShouldFailGettingDelayedElementWithoutWait() { - $this->driver->get($this->getTestPath('delayed_element.html')); + $this->driver->get($this->getTestPageUrl('delayed_element.html')); $this->setExpectedException(NoSuchElementException::class); $this->driver->findElement(WebDriverBy::id('delayed')); @@ -39,7 +39,7 @@ public function testShouldFailGettingDelayedElementWithoutWait() */ public function testShouldGetDelayedElementWithImplicitWait() { - $this->driver->get($this->getTestPath('delayed_element.html')); + $this->driver->get($this->getTestPageUrl('delayed_element.html')); $this->driver->manage()->timeouts()->implicitlyWait(1); $element = $this->driver->findElement(WebDriverBy::id('delayed')); From 87ec0a905e74b3054ba6eda6aad9941caf4b7c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 10 Feb 2017 18:00:44 +0100 Subject: [PATCH 138/600] Extend wait as an attempt to make the script more stable in slower network environments... --- tests/functional/RemoteWebDriverTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 0f38d0f3c..858bcd786 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -162,14 +162,14 @@ public function testShouldExecuteScriptAndDoNotBlockExecution() $this->driver->executeScript(' setTimeout( function(){document.getElementById("id_test").innerHTML = "Text changed by script"}, - 250 + 500 )'); // Make sure the script don't block the test execution $this->assertSame('Test by ID', $element->getText()); // If we wait, the script should be executed - usleep(300000); // wait 300 ms + usleep(550000); // wait 550 ms $this->assertSame('Text changed by script', $element->getText()); } From 91c98338ea4638890f6d29e662e048c747b9cf41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 11 Feb 2017 14:40:41 +0100 Subject: [PATCH 139/600] Enable sauce connect addon only on SauceLabs builds This will improve performace of other builds, also otherwise we reach the SauceLabs concurrency tunel limit. --- .travis.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7229a2c3..c2aa30aa9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,12 +20,24 @@ matrix: - php: 7.0 env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + addons: + sauce_connect: true + jwt: + secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - php: 7.0 env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="45.0" PLATFORM="Linux" before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + addons: + sauce_connect: true + jwt: + secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - php: 7.0 env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + addons: + sauce_connect: true + jwt: + secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= # Add PHP 7 build to check codestyle only in PHP 7 build - php: 7.0 @@ -79,6 +91,3 @@ addons: apt: packages: - oracle-java8-installer - sauce_connect: true - jwt: - secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= From 6f3e3403cf8e9215203ec05a7bddbd3c4cda251c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 11 Feb 2017 20:41:58 +0100 Subject: [PATCH 140/600] Install Firefox only on Firefox build (to not slow down other builds) --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c2aa30aa9..f8fc22fe6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ matrix: # Add build to run tests against Firefox inside Travis environment (other runs are agains HtmlUnit by default) - php: 7.0 env: BROWSER_NAME="firefox" + addons: + firefox: "latest-esr" # Build with lowest possible dependencies - php: 7.0 @@ -87,7 +89,6 @@ after_success: - travis_retry php vendor/bin/coveralls -v addons: - firefox: "latest-esr" apt: packages: - oracle-java8-installer From a59ed83f5079fdefa75cf4ac694325b4ef699180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 22 Feb 2017 23:14:33 +0000 Subject: [PATCH 141/600] Upgrade to Selenium 3.1.0 --- .travis.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index f8fc22fe6..b771dd496 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,9 @@ matrix: env: BROWSER_NAME="firefox" addons: firefox: "latest-esr" + apt: + packages: + - oracle-java8-installer # Build with lowest possible dependencies - php: 7.0 @@ -68,13 +71,8 @@ install: before_script: - sh -e /etc/init.d/xvfb start - # TODO: upgrade to Selenium 3.0.2 (with latest HtmlUnit) once released, as HtmlUnit in 3.0.1 is broken - - if [ ! -f jar/selenium-server-standalone-2.53.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar; fi - - if [ ! -f jar/htmlunit-driver-standalone-2.20.jar ]; then wget -q -t 3 -P jar https://github.com/SeleniumHQ/htmlunit-driver/releases/download/2.20/htmlunit-driver-standalone-2.20.jar; fi - # Temporarily run HtmlUnit from standalone jar file (it was not part of Selenium server standalone in version 2.53) - - java -cp "jar/selenium-server-standalone-2.53.1.jar:jar/htmlunit-driver-standalone-2.20.jar" org.openqa.grid.selenium.GridLauncher -log ./logs/selenium.log & - # TODO: use this after upgrade to Selenium 3.0.2 - #- /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.0.2.jar -log selenium.log & + - if [ ! -f jar/selenium-server-standalone-3.1.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.1/selenium-server-standalone-3.1.0.jar; fi + - /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done - php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & From 8900b1fc26f071724c04774ea129ddfc402684f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 23 Feb 2017 19:03:54 +0000 Subject: [PATCH 142/600] Identify SauceLabs tests by name and tags --- tests/functional/WebDriverTestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 62f98b5d1..3673d0a8e 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -87,6 +87,8 @@ protected function setUpSauceLabs() $this->desiredCapabilities->setBrowserName(getenv('BROWSER_NAME')); $this->desiredCapabilities->setVersion(getenv('VERSION')); $this->desiredCapabilities->setPlatform(getenv('PLATFORM')); + $this->desiredCapabilities->setCapability('name', get_class($this) . '::' . $this->getName()); + $this->desiredCapabilities->setCapability('tags', [get_class($this)]); if (getenv('TRAVIS_JOB_NUMBER')) { $this->desiredCapabilities->setCapability('tunnel-identifier', getenv('TRAVIS_JOB_NUMBER')); From bab090739c5bbc7d6c4efc8da1505665b15ca144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 23 Feb 2017 20:04:13 +0000 Subject: [PATCH 143/600] Report test results to saucelabs API to show the results on their dashboard --- composer.json | 2 +- phpunit.xml.dist | 5 ++ .../ReportSauceLabsStatusListener.php | 88 +++++++++++++++++++ tests/functional/WebDriverTestCase.php | 16 +++- 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 tests/functional/ReportSauceLabsStatusListener.php diff --git a/composer.json b/composer.json index 3523361f9..a80697c47 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ }, "autoload-dev": { "psr-4": { - "Facebook\\WebDriver\\": "tests/unit" + "Facebook\\WebDriver\\": ["tests/unit", "tests/functional"] }, "classmap": ["tests/functional/"] } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 894ba470a..430a8fb5c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -29,4 +29,9 @@ ./lib + + + + + diff --git a/tests/functional/ReportSauceLabsStatusListener.php b/tests/functional/ReportSauceLabsStatusListener.php new file mode 100644 index 000000000..b88b1cdf7 --- /dev/null +++ b/tests/functional/ReportSauceLabsStatusListener.php @@ -0,0 +1,88 @@ +driver instanceof RemoteWebDriver) { + return; + } + + /** @var WebDriverTestCase $test */ + if (!$test->isSauceLabsBuild()) { + return; + } + + $testStatus = $test->getStatus(); + + if ($this->testWasSkippedOrIncomplete($testStatus)) { + return; + } + + $endpointUrl = sprintf( + 'https://saucelabs.com/rest/v1/%s/jobs/%s', + getenv('SAUCE_USERNAME'), + $test->driver->getSessionID() + ); + + $data = [ + 'passed' => ($testStatus === \PHPUnit_Runner_BaseTestRunner::STATUS_PASSED), + 'custom-data' => ['message' => $test->getStatusMessage()], + ]; + + $this->submitToSauceLabs($endpointUrl, $data); + } + + /** + * @param int $testStatus + * @return bool + */ + private function testWasSkippedOrIncomplete($testStatus) + { + if ($testStatus === \PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED + || $testStatus === \PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE) { + return true; + } + + return false; + } + + /** + * @param string $url + * @param array $data + */ + private function submitToSauceLabs($url, array $data) + { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); + curl_setopt($curl, CURLOPT_USERPWD, getenv('SAUCE_USERNAME') . ':' . getenv('SAUCE_ACCESS_KEY')); + curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); + + curl_exec($curl); + + if (curl_errno($curl)) { + throw new \Exception(sprintf('Error publishing test results to SauceLabs: %s', curl_error($curl))); + } + + curl_close($curl); + } +} diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 3673d0a8e..a2639bae7 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -25,12 +25,12 @@ */ class WebDriverTestCase extends \PHPUnit_Framework_TestCase { + /** @var RemoteWebDriver $driver */ + public $driver; /** @var bool Indicate whether WebDriver should be created on setUp */ protected $createWebDriver = true; /** @var string */ protected $serverUrl = 'http://localhost:4444/wd/hub'; - /** @var RemoteWebDriver $driver */ - protected $driver; /** @var DesiredCapabilities */ protected $desiredCapabilities; @@ -38,7 +38,7 @@ protected function setUp() { $this->desiredCapabilities = new DesiredCapabilities(); - if (getenv('SAUCELABS')) { + if ($this->isSauceLabsBuild()) { $this->setUpSauceLabs(); } else { if (getenv('BROWSER_NAME')) { @@ -66,6 +66,14 @@ protected function tearDown() } } + /** + * @return bool + */ + public function isSauceLabsBuild() + { + return getenv('SAUCELABS') ? true : false; + } + /** * Get the URL of given test HTML on running webserver. * @@ -101,7 +109,7 @@ protected function setUpSauceLabs() */ protected function skipOnSauceLabs($message = 'Not supported by SauceLabs') { - if (getenv('SAUCELABS')) { + if ($this->isSauceLabsBuild()) { $this->markTestSkipped($message); } } From 1cdbf31156271381c65eab169923c3f744648a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 24 Feb 2017 00:36:39 +0000 Subject: [PATCH 144/600] Extend wait once more to make the script more stable in slower network environments like with SauceLabs --- tests/functional/RemoteWebDriverTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 858bcd786..52f1d9cb7 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -169,7 +169,7 @@ function(){document.getElementById("id_test").innerHTML = "Text changed by scrip $this->assertSame('Test by ID', $element->getText()); // If we wait, the script should be executed - usleep(550000); // wait 550 ms + usleep(1000000); // wait 1000 ms $this->assertSame('Text changed by script', $element->getText()); } From 3c4c512e15011b674bb9f409ef365854ed7bd3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 24 Feb 2017 11:17:29 +0000 Subject: [PATCH 145/600] Do not even start (ie. exclude) tests not working on saucelabs, instead of skipping them --- .travis.yml | 3 ++- tests/functional/RemoteWebDriverTest.php | 6 ++---- tests/functional/WebDriverTestCase.php | 10 ---------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index b771dd496..353936986 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,7 +77,8 @@ before_script: - php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & script: - - ./vendor/bin/phpunit --coverage-clover ./logs/coverage-clover.xml + - if [ -n "$SAUCELABS" ]; then EXTRA_PARAMS="--exclude-group exclude-saucelabs"; fi + - ./vendor/bin/phpunit --coverage-clover ./logs/coverage-clover.xml $EXTRA_PARAMS after_script: - cat ./logs/selenium.log diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 52f1d9cb7..7b60b69d7 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -75,12 +75,11 @@ public function testShouldGetSessionId() } /** + * @group exclude-saucelabs * @covers ::getAllSessions */ public function testShouldGetAllSessions() { - $this->skipOnSauceLabs('getAllSessions() is not supported on SauceLabs'); - $sessions = RemoteWebDriver::getAllSessions($this->serverUrl); $this->assertInternalType('array', $sessions); @@ -92,14 +91,13 @@ public function testShouldGetAllSessions() } /** + * @group exclude-saucelabs * @covers ::getAllSessions * @covers ::getCommandExecutor * @covers ::quit */ public function testShouldQuitAndUnsetExecutor() { - $this->skipOnSauceLabs('getAllSessions() is not supported on SauceLabs'); - $this->assertCount(1, RemoteWebDriver::getAllSessions($this->serverUrl)); $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index a2639bae7..84883574a 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -103,14 +103,4 @@ protected function setUpSauceLabs() $this->desiredCapabilities->setCapability('build', getenv('TRAVIS_JOB_NUMBER')); } } - - /** - * @param string $message - */ - protected function skipOnSauceLabs($message = 'Not supported by SauceLabs') - { - if ($this->isSauceLabsBuild()) { - $this->markTestSkipped($message); - } - } } From 6fb60b020e39b89dc3e913c294bc780bf545b9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 26 Feb 2017 18:45:37 +0000 Subject: [PATCH 146/600] Add travis and saucelabs badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d2a8d6132..cfdf0bc3b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # php-webdriver – Selenium WebDriver bindings for PHP [![Latest Stable Version](https://img.shields.io/packagist/v/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) +[![Travis Build](https://img.shields.io/travis/facebook/php-webdriver/community.svg?style=flat-square)](https://travis-ci.org/facebook/php-webdriver) +[![Sauce Test Status](https://saucelabs.com/buildstatus/php-webdriver)](https://saucelabs.com/u/php-webdriver) [![Total Downloads](https://img.shields.io/packagist/dt/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) [![License](https://img.shields.io/packagist/l/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) From 75af11ac9661ff76cf857ead31b30cfac9528ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 6 Mar 2017 21:49:43 +0000 Subject: [PATCH 147/600] Do not throw fatal error when null is passed to sendKeys (fixes #419) --- CHANGELOG.md | 3 ++ lib/Interactions/WebDriverCompositeAction.php | 2 +- lib/WebDriverKeys.php | 12 +++-- tests/unit/WebDriverKeysTest.php | 54 +++++++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 tests/unit/WebDriverKeysTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b99a4f66..87407e0c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Cookies retrieved using `getCookieNamed()` and `getCookies()` methods of `WebDriverOptions` are now encapsulated in `Cookie` object instead of an plain array. The object implements `ArrayAccess` interface to provide backward compatibility. - `ext-zip` is now specified as required dependency in composer.json (but the extension was already required by the code, though). +### Fixed +- Do not throw fatal error when `null` is passed to `sendKeys()`. + ## 1.3.0 - 2017-01-13 ### Added - Added `getCapabilities()` method of `RemoteWebDriver`, to retrieve actual capabilities acknowledged by the remote driver on startup. diff --git a/lib/Interactions/WebDriverCompositeAction.php b/lib/Interactions/WebDriverCompositeAction.php index 75b879082..75a4837e1 100644 --- a/lib/Interactions/WebDriverCompositeAction.php +++ b/lib/Interactions/WebDriverCompositeAction.php @@ -23,7 +23,7 @@ class WebDriverCompositeAction implements WebDriverAction { /** - * @var array + * @var WebDriverAction[] */ private $actions = []; diff --git a/lib/WebDriverKeys.php b/lib/WebDriverKeys.php index 57d37c1eb..c25748e8c 100644 --- a/lib/WebDriverKeys.php +++ b/lib/WebDriverKeys.php @@ -88,24 +88,28 @@ class WebDriverKeys /** * Encode input of `sendKeys()`. - * @param string|array $keys + * @param string|array|int|float $keys * @return array */ public static function encode($keys) { if (is_numeric($keys)) { - $keys = '' . $keys; + $keys = (string) $keys; } if (is_string($keys)) { $keys = [$keys]; } + if (!is_array($keys)) { + return []; + } + $encoded = []; foreach ($keys as $key) { if (is_array($key)) { - // handle modified keys - $key = implode('', $key) . self::NULL; + // handle key modifiers + $key = implode('', $key) . self::NULL; // the NULL clears the input state (eg. previous modifiers) } $encoded[] = (string) $key; } diff --git a/tests/unit/WebDriverKeysTest.php b/tests/unit/WebDriverKeysTest.php new file mode 100644 index 000000000..9a205c7de --- /dev/null +++ b/tests/unit/WebDriverKeysTest.php @@ -0,0 +1,54 @@ +assertSame($expectedOutput, WebDriverKeys::encode($keys)); + } + + /** + * @return array[] + */ + public function provideKeys() + { + return [ + 'empty string' => ['', ['']], + 'simple string' => ['foo', ['foo']], + 'string as an array' => [['foo'], ['foo']], + 'string with modifier as an array' => [[WebDriverKeys::SHIFT, 'foo'], [WebDriverKeys::SHIFT, 'foo']], + 'string with concatenated modifier' => [[WebDriverKeys::SHIFT . 'foo'], [WebDriverKeys::SHIFT . 'foo']], + 'simple numeric value' => [3, ['3']], + 'multiple numeric values' => [[1, 3.33], ['1', '3.33']], + 'multiple mixed values ' => [['foo', WebDriverKeys::END, '1.234'], ['foo', WebDriverKeys::END, '1.234']], + 'array of strings with modifiers should separate them with NULL character' => [ + [[WebDriverKeys::SHIFT, 'foo'], [WebDriverKeys::META, 'bar']], + [WebDriverKeys::SHIFT . 'foo' . WebDriverKeys::NULL, WebDriverKeys::META . 'bar' . WebDriverKeys::NULL], + ], + 'null' => [null, []], + ]; + } +} From ecc272a4ece0975ee320e87e2ed5f5ee737cfdf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Mar 2017 10:28:01 +0000 Subject: [PATCH 148/600] Add composer scripts for simple codestyle check/fix --- .travis.yml | 4 +--- CONTRIBUTING.md | 21 +++++++++++++++++---- composer.json | 10 ++++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 353936986..2eaa8fd02 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,9 +48,7 @@ matrix: - php: 7.0 env: CHECK_CODESTYLE=1 before_script: ~ - script: - - ./vendor/bin/php-cs-fixer fix --diff --dry-run - - ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/ + script: composer codestyle:check after_script: ~ after_success: ~ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a73c9eafd..3bea30bba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,15 +29,28 @@ To execute all tests simply run: If you want to execute just the unit tests, run: ./vendor/bin/phpunit --testsuite unit + +For the functional tests you must first [download](http://selenium-release.storage.googleapis.com/index.html) and start +the selenium standalone server, start the local PHP server which will serve the test pages and then run the `functional` +test suite: + + java -jar selenium-server-standalone-2.53.1.jar -log selenium.log & + php -S localhost:8000 -t tests/functional/web/ & + ./vendor/bin/phpunit --testsuite functional -For the functional tests you must first download and start the selenium server, then run the `functional` test suite: +The functional tests will be started in HtmlUnit headless browser by default. If you want to run them in eg. Firefox, +simply set the `BROWSER` environment variable: - java -jar selenium-server-standalone-2.48.2.jar -log selenium.log & + ... + export BROWSER_NAME="firefox" ./vendor/bin/phpunit --testsuite functional ### Check coding style Your code-style should comply with [PSR-2](http://www.php-fig.org/psr/psr-2/). To make sure your code matches this requirement run: - ./vendor/bin/php-cs-fixer fix --diff --dry-run - ./vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/ + composer codestyle:check + +To auto-fix the codestyle simply run: + + composer codestyle:fix diff --git a/composer.json b/composer.json index a80697c47..24825d658 100644 --- a/composer.json +++ b/composer.json @@ -33,5 +33,15 @@ "Facebook\\WebDriver\\": ["tests/unit", "tests/functional"] }, "classmap": ["tests/functional/"] + }, + "scripts": { + "codestyle:check": [ + "vendor/bin/php-cs-fixer fix --diff --dry-run", + "vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/" + ], + "codestyle:fix": [ + "vendor/bin/php-cs-fixer fix --diff || exit 0", + "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" + ] } } From b10102f60f097108d783aa97fa5f3186a146c961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 11 Mar 2017 22:46:23 +0000 Subject: [PATCH 149/600] Deprecate isJavascriptEnabled method. See https://github.com/SeleniumHQ/selenium/commit/5b0f88ef3256595148b357dec6209735cab25bea --- CHANGELOG.md | 1 + lib/Remote/DesiredCapabilities.php | 2 ++ lib/WebDriverCapabilities.php | 2 ++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87407e0c1..b63abff80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Cookies should now be set using `Cookie` value object instead of an array when passed to to `addCookie()` method of `WebDriverOptions`. - Cookies retrieved using `getCookieNamed()` and `getCookies()` methods of `WebDriverOptions` are now encapsulated in `Cookie` object instead of an plain array. The object implements `ArrayAccess` interface to provide backward compatibility. - `ext-zip` is now specified as required dependency in composer.json (but the extension was already required by the code, though). +- Deprecate `WebDriverCapabilities::isJavascriptEnabled()` method. ### Fixed - Do not throw fatal error when `null` is passed to `sendKeys()`. diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 94d8e1de2..3990343af 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -123,6 +123,8 @@ public function is($capability_name) } /** + * @todo Remove in next major release (BC) + * @deprecated All browsers are always JS enabled except HtmlUnit and it's not meaningful to disable JS execution. * @return bool Whether javascript is enabled. */ public function isJavascriptEnabled() diff --git a/lib/WebDriverCapabilities.php b/lib/WebDriverCapabilities.php index b489a1e6e..9ac851d90 100644 --- a/lib/WebDriverCapabilities.php +++ b/lib/WebDriverCapabilities.php @@ -45,6 +45,8 @@ public function getVersion(); public function is($capability_name); /** + * @todo Remove in next major release (BC) + * @deprecated All browsers are always JS enabled except HtmlUnit and it's not meaningful to disable JS execution. * @return bool Whether javascript is enabled. */ public function isJavascriptEnabled(); From 89a6ce780387202ccbdb511eab613a5691613034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 16 Mar 2017 13:02:52 +0000 Subject: [PATCH 150/600] Workaround in example script for Selenium bug (fixes #402) --- example.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/example.php b/example.php index 7bebd10b5..263d0c1d6 100644 --- a/example.php +++ b/example.php @@ -13,8 +13,8 @@ $capabilities = DesiredCapabilities::firefox(); $driver = RemoteWebDriver::create($host, $capabilities, 5000); -// navigate to 'http://docs.seleniumhq.org/' -$driver->get('http://docs.seleniumhq.org/'); +// navigate to 'http://www.seleniumhq.org/' +$driver->get('http://www.seleniumhq.org/'); // adding cookie $driver->manage()->deleteAllCookies(); @@ -31,17 +31,24 @@ ); $link->click(); +// wait until the page is loaded +$driver->wait()->until( + WebDriverExpectedCondition::titleContains('About') +); + // print the title of the current page echo "The title is '" . $driver->getTitle() . "'\n"; // print the URI of the current page echo "The current URI is '" . $driver->getCurrentURL() . "'\n"; -// Search 'php' in the search box -$input = $driver->findElement( - WebDriverBy::id('q') -); -$input->sendKeys('php')->submit(); +// write 'php' in the search box +$driver->findElement(WebDriverBy::id('q')) + ->sendKeys('php'); + +// submit the form +$driver->findElement(WebDriverBy::id('submit')) + ->click(); // submit() does not work in Selenium 3 because of bug https://github.com/SeleniumHQ/selenium/issues/3398 // wait at most 10 seconds until at least one result is shown $driver->wait(10)->until( From f6ae7db59f4be0a5a8f791448c72d9d4d920e514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 16 Mar 2017 14:44:20 +0000 Subject: [PATCH 151/600] Use previous Firefox ESR, as new ESR is based on Firefox 52 (which requires Geckodriver) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2eaa8fd02..a42bfbe20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ matrix: - php: 7.0 env: BROWSER_NAME="firefox" addons: - firefox: "latest-esr" + firefox: "45.8.0esr" apt: packages: - oracle-java8-installer From 4f141e058d55ebd762c11201ac129c7cb98bd925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 18 Mar 2017 12:00:54 +0000 Subject: [PATCH 152/600] Remove Firefox 45 build, bacause it is unstable and slow --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index a42bfbe20..0c987bc87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,13 +29,6 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: 7.0 - env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="45.0" PLATFORM="Linux" - before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & - addons: - sauce_connect: true - jwt: - secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - php: 7.0 env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & From 48b9c7aebed26b252ead3e15a621db46b405fd78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 18 Mar 2017 12:57:15 +0000 Subject: [PATCH 153/600] Setup branch alias to allow simplier installation of development versions --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 24825d658..1381c13d5 100644 --- a/composer.json +++ b/composer.json @@ -43,5 +43,10 @@ "vendor/bin/php-cs-fixer fix --diff || exit 0", "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" ] + }, + "extra": { + "branch-alias": { + "dev-community": "1.4-dev" + } } } From 51ef9da2b689d2680ad006d4cc3c9ec95977e015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 19 Mar 2017 11:17:02 +0000 Subject: [PATCH 154/600] Rename textToBePresentInElementValue expected condition to make its name systematic with other conditions --- CHANGELOG.md | 1 + lib/WebDriverExpectedCondition.php | 14 ++++++++ tests/unit/WebDriverExpectedConditionTest.php | 35 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b63abff80..2f6b5e772 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Cookies retrieved using `getCookieNamed()` and `getCookies()` methods of `WebDriverOptions` are now encapsulated in `Cookie` object instead of an plain array. The object implements `ArrayAccess` interface to provide backward compatibility. - `ext-zip` is now specified as required dependency in composer.json (but the extension was already required by the code, though). - Deprecate `WebDriverCapabilities::isJavascriptEnabled()` method. +- Deprecate `textToBePresentInElementValue` expected condition in favor of `elementValueContains`. ### Fixed - Do not throw fatal error when `null` is passed to `sendKeys()`. diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 58ba939e9..347a5d28a 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -292,11 +292,25 @@ function (WebDriver $driver) use ($by, $regexp) { /** * An expectation for checking if the given text is present in the specified elements value attribute. * + * @codeCoverageIgnore + * @deprecated Use WebDriverExpectedCondition::elementValueContains() instead * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element value. * @return WebDriverExpectedCondition Condition returns whether the text is present in value attribute. */ public static function textToBePresentInElementValue(WebDriverBy $by, $text) + { + return self::elementValueContains($by, $text); + } + + /** + * An expectation for checking if the given text is present in the specified elements value attribute. + * + * @param WebDriverBy $by The locator used to find the element. + * @param string $text The text to be presented in the element value. + * @return WebDriverExpectedCondition Condition returns whether the text is present in value attribute. + */ + public static function elementValueContains(WebDriverBy $by, $text) { return new static( function (WebDriver $driver) use ($by, $text) { diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index 93d98b392..c2605a97d 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -292,6 +292,41 @@ public function testShouldDetectElementTextMatchesCondition() $this->assertTrue($this->wait->until($condition)); } + public function testShouldDetectElementValueContainsCondition() + { + // Set-up the consecutive calls to apply() as follows: + // Call #1: throws NoSuchElementException + // Call #2: return Element, but getAttribute will throw StaleElementReferenceException + // Call #3: return Element, getAttribute('value') will return not-matching text + // Call #4: return Element, getAttribute('value') will return matching text + + $element = $this->createRemoteWebElementMock(); + + $element->expects($this->at(0)) + ->method('getAttribute') + ->with('value') + ->willThrowException(new StaleElementReferenceException('')); + + $element->expects($this->at(1)) + ->method('getAttribute') + ->with('value') + ->willReturn('wrong text'); + + $element->expects($this->at(2)) + ->method('getAttribute') + ->with('value') + ->willReturn('matching text'); + + $this->setupDriverToReturnElementAfterAnException($element, 4); + + $condition = WebDriverExpectedCondition::elementValueContains( + WebDriverBy::cssSelector('.foo'), + 'matching' + ); + + $this->assertTrue($this->wait->until($condition)); + } + public function testShouldDetectNumberOfWindowsToBeCondition() { $this->driverMock->expects($this->any()) From 7a855dd1b82d350e4fff9509b5031b37bcd0434f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 19 Mar 2017 11:17:30 +0000 Subject: [PATCH 155/600] Add UT for invisibilityOfElementLocated expected contition --- tests/unit/WebDriverExpectedConditionTest.php | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index c2605a97d..e786167a8 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -185,6 +185,73 @@ public function testShouldDetectVisibilityOfElementLocatedCondition() $this->assertSame($element, $this->wait->until($condition)); } + public function testShouldDetectInvisibilityOfElementLocatedConditionOnNoSuchElementException() + { + $element = $this->createRemoteWebElementMock(); + + $this->driverMock->expects($this->at(0)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $element->expects($this->at(0)) + ->method('isDisplayed') + ->willReturn(true); + + $this->driverMock->expects($this->at(1)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willThrowException(new NoSuchElementException('')); + + $condition = WebDriverExpectedCondition::invisibilityOfElementLocated(WebDriverBy::cssSelector('.foo')); + + $this->assertTrue($this->wait->until($condition)); + } + + public function testShouldDetectInvisibilityOfElementLocatedConditionOnStaleElementReferenceException() + { + $element = $this->createRemoteWebElementMock(); + + $this->driverMock->expects($this->exactly(2)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $element->expects($this->at(0)) + ->method('isDisplayed') + ->willReturn(true); + + $element->expects($this->at(1)) + ->method('isDisplayed') + ->willThrowException(new StaleElementReferenceException('')); + + $condition = WebDriverExpectedCondition::invisibilityOfElementLocated(WebDriverBy::cssSelector('.foo')); + + $this->assertTrue($this->wait->until($condition)); + } + + public function testShouldDetectInvisibilityOfElementLocatedConditionWhenElementBecamesInvisible() + { + $element = $this->createRemoteWebElementMock(); + + $this->driverMock->expects($this->exactly(2)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $element->expects($this->at(0)) + ->method('isDisplayed') + ->willReturn(true); + + $element->expects($this->at(1)) + ->method('isDisplayed') + ->willReturn(false); + + $condition = WebDriverExpectedCondition::invisibilityOfElementLocated(WebDriverBy::cssSelector('.foo')); + + $this->assertTrue($this->wait->until($condition)); + } + public function testShouldDetectVisibilityOfCondition() { $element = $this->createRemoteWebElementMock(); From 3ea034c056189e11c0ce7985332a9f4b5b2b5db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 22 Mar 2017 11:55:12 +0100 Subject: [PATCH 156/600] Release version 1.4.0 --- CHANGELOG.md | 2 ++ composer.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f6b5e772..89c93fadd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.4.0 - 2017-03-22 ### Changed - Cookies should now be set using `Cookie` value object instead of an array when passed to to `addCookie()` method of `WebDriverOptions`. - Cookies retrieved using `getCookieNamed()` and `getCookies()` methods of `WebDriverOptions` are now encapsulated in `Cookie` object instead of an plain array. The object implements `ArrayAccess` interface to provide backward compatibility. diff --git a/composer.json b/composer.json index 1381c13d5..0a87cb3ed 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ }, "extra": { "branch-alias": { - "dev-community": "1.4-dev" + "dev-community": "1.5-dev" } } } From 905b0e3ea21286d7839c939ae0a70ff47c20c34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 24 Apr 2017 23:25:02 +0200 Subject: [PATCH 157/600] Update https link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3bea30bba..6c59bbe84 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ send a pull request (see bellow) with your contribution. 4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md) 5. Submit your [pull request](https://github.com/facebook/php-webdriver/pulls) against community branch -Note before any pull request can be accepted, a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed. +Note before any pull request can be accepted, a [Contributors Licensing Agreement](https://developers.facebook.com/opensource/cla) must be signed. When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. FYI, here is the overview of [the official Java API](http://seleniumhq.github.io/selenium/docs/api/java/) From d06347f10ef20989f1fe705b7692c23a4ebe00dc Mon Sep 17 00:00:00 2001 From: toniperic Date: Thu, 27 Apr 2017 10:13:47 +0200 Subject: [PATCH 158/600] Correct constant checking Prior to this change I would be getting `Constant CURLOPT_CONNECTTIMEOUT_MS already defined` since PHP would try to re-define a constant. --- lib/Net/URLChecker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Net/URLChecker.php b/lib/Net/URLChecker.php index 575daac56..00ad62593 100644 --- a/lib/Net/URLChecker.php +++ b/lib/Net/URLChecker.php @@ -66,7 +66,7 @@ private function getHTTPResponseCode($url) curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // The PHP doc indicates that CURLOPT_CONNECTTIMEOUT_MS constant is added in cURL 7.16.2 // available since PHP 5.2.3. - if (!defined(CURLOPT_CONNECTTIMEOUT_MS)) { + if (!defined('CURLOPT_CONNECTTIMEOUT_MS')) { define('CURLOPT_CONNECTTIMEOUT_MS', 156); // default value for CURLOPT_CONNECTTIMEOUT_MS } curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS); From 94f64e54e50b2b4b0883d25aefb743d006eaa98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 28 Apr 2017 12:37:04 +0200 Subject: [PATCH 159/600] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c93fadd..9a4410c09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Fixed +- Do not throw notice `Constant CURLOPT_CONNECTTIMEOUT_MS already defined`. ## 1.4.0 - 2017-03-22 ### Changed From 75c22b51131ed6b11276672a8a39b5b7976c0ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 28 Apr 2017 02:52:01 +0200 Subject: [PATCH 160/600] Make sure sudo mode is disabled in all travis builds --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0c987bc87..1c2146bb3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ php: - 7.0 - 7.1 +sudo: false + matrix: include: # Add build to run tests against Firefox inside Travis environment (other runs are agains HtmlUnit by default) From 4a3bb63e73b9e30f6ac601a7b237a44d3c07f1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 28 Apr 2017 12:30:57 +0200 Subject: [PATCH 161/600] Print logs in travis only if created --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1c2146bb3..c957fd41e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,8 +74,8 @@ script: - ./vendor/bin/phpunit --coverage-clover ./logs/coverage-clover.xml $EXTRA_PARAMS after_script: - - cat ./logs/selenium.log - - cat ./logs/php-server.log + - if [ -f ./logs/selenium.log ]; then cat ./logs/selenium.log; fi + - if [ -f ./logs/php-server.log ]; then cat ./logs/php-server.log; fi after_success: - travis_retry php vendor/bin/coveralls -v From 66e37cfb00b698bfc96dd47f71ae1bd4659e6bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 28 Apr 2017 15:07:40 +0200 Subject: [PATCH 162/600] Bind PHP server to 127.0.0.1 to overcome Bad Gateway error when using 'localhost' --- .travis.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c957fd41e..5c5ca4c0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,14 +26,18 @@ matrix: # Saucelabs builds - php: 7.0 env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" - before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + before_script: + - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" addons: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - php: 7.0 env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" - before_script: php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + before_script: + - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" addons: sauce_connect: true jwt: @@ -66,8 +70,9 @@ before_script: - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.1.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.1/selenium-server-standalone-3.1.0.jar; fi - /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & - - until $(echo | nc localhost 4444); do sleep 1; echo waiting for selenium-server...; done - - php -S localhost:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" + - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" script: - if [ -n "$SAUCELABS" ]; then EXTRA_PARAMS="--exclude-group exclude-saucelabs"; fi From eadb0b7a7c3e6578185197fd40158b08c3164c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 28 Apr 2017 16:54:49 +0200 Subject: [PATCH 163/600] Release version 1.4.1 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4410c09..c7d018435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.4.1 - 2017-04-28 ### Fixed - Do not throw notice `Constant CURLOPT_CONNECTTIMEOUT_MS already defined`. From 10c8c8449713fc79a672b2636e10284ab92b110e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 21 Jun 2017 11:15:17 +0200 Subject: [PATCH 164/600] Add LICENCE.md --- LICENCE.md | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENCE.md diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 000000000..0b3f67bd7 --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2004-present Facebook + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 8fee7dceac5e3f867fe91d45743e3bc74b3b6efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 4 Aug 2017 21:37:11 +0200 Subject: [PATCH 165/600] Build on PHP 7.1 by default --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c5ca4c0e..fde500451 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ sudo: false matrix: include: - # Add build to run tests against Firefox inside Travis environment (other runs are agains HtmlUnit by default) - - php: 7.0 + # Add build to run tests against Firefox inside Travis environment (other runs are against HtmlUnit by default) + - php: 7.1 env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" @@ -20,11 +20,11 @@ matrix: - oracle-java8-installer # Build with lowest possible dependencies - - php: 7.0 + - php: 7.1 env: dependencies="--prefer-lowest" # Saucelabs builds - - php: 7.0 + - php: 7.1 env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -33,7 +33,7 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: 7.0 + - php: 7.1 env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -43,8 +43,8 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - # Add PHP 7 build to check codestyle only in PHP 7 build - - php: 7.0 + # Codestyle check build + - php: 7.1 env: CHECK_CODESTYLE=1 before_script: ~ script: composer codestyle:check From 6a3b3520d85c63434f00eb15bd4eebfcc0d5e750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 4 Aug 2017 21:38:09 +0200 Subject: [PATCH 166/600] Build on Ubuntu Trusty, so we don't need to install Java 8 by ourselves --- .travis.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index fde500451..5ae58d50e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: php +dist: trusty + php: - 5.5 - 5.6 @@ -15,9 +17,6 @@ matrix: env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" - apt: - packages: - - oracle-java8-installer # Build with lowest possible dependencies - php: 7.1 @@ -69,7 +68,7 @@ install: before_script: - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.1.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.1/selenium-server-standalone-3.1.0.jar; fi - - /usr/lib/jvm/java-8-oracle/bin/java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & + - java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" @@ -84,8 +83,3 @@ after_script: after_success: - travis_retry php vendor/bin/coveralls -v - -addons: - apt: - packages: - - oracle-java8-installer From 3289cd39ab82d53b09853d98cf5bb780685eb791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 4 Aug 2017 21:49:57 +0200 Subject: [PATCH 167/600] Add headless chrome travis build --- .travis.yml | 24 ++++++++++++++++-------- tests/functional/WebDriverAlertTest.php | 6 ++++++ tests/functional/WebDriverTestCase.php | 7 +++++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5ae58d50e..b12b404db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: php - +sudo: false dist: trusty php: @@ -8,16 +8,26 @@ php: - 7.0 - 7.1 -sudo: false +env: + global: + - DISPLAY=:99.0 + - BROWSER_NAME="htmlunit" + - CHROMEDRIVER_VERSION="2.31" matrix: include: - # Add build to run tests against Firefox inside Travis environment (other runs are against HtmlUnit by default) + # Add build to run tests against Firefox inside Travis environment - php: 7.1 env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" + # Add build to run tests against Chrome inside Travis environment + - php: 7.1 + env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" + addons: + chrome: beta + # Build with lowest possible dependencies - php: 7.1 env: dependencies="--prefer-lowest" @@ -50,10 +60,6 @@ matrix: after_script: ~ after_success: ~ -env: - global: - - DISPLAY=:99.0 - cache: directories: - $HOME/.composer/cache @@ -66,9 +72,11 @@ install: - travis_retry composer update --no-interaction $dependencies before_script: + - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi + - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=./chromedriver/chromedriver; fi - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.1.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.1/selenium-server-standalone-3.1.0.jar; fi - - java -Dwebdriver.firefox.marionette=false -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & + - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index eddf3a9ae..61126b9bd 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -25,6 +25,12 @@ class WebDriverAlertTest extends WebDriverTestCase { protected function setUp() { + if (getenv('CHROME_HEADLESS') === '1') { + // Alerts in headless mode should be available in next Chrome version (61), see: + // https://bugs.chromium.org/p/chromium/issues/detail?id=718235 + $this->markTestSkipped('Alerts not yet supported by headless Chrome'); + } + parent::setUp(); $this->driver->get($this->getTestPageUrl('alert.html')); diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 84883574a..0c11e3fb8 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -15,6 +15,7 @@ namespace Facebook\WebDriver; +use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Exception\NoSuchWindowException; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; @@ -47,6 +48,12 @@ protected function setUp() $browserName = WebDriverBrowserType::HTMLUNIT; } + if ($browserName === WebDriverBrowserType::CHROME) { + $chromeOptions = new ChromeOptions(); + $chromeOptions->addArguments(['--headless', 'window-size=1024,768']); + $this->desiredCapabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); + } + $this->desiredCapabilities->setBrowserName($browserName); } From 23b1d70c7671443ed686313f71c5ae293e676d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 4 Aug 2017 22:43:45 +0200 Subject: [PATCH 168/600] Upgrade Selenium server in Travis buils to 3.4.0 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b12b404db..68db86dfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,8 +75,8 @@ before_script: - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=./chromedriver/chromedriver; fi - sh -e /etc/init.d/xvfb start - - if [ ! -f jar/selenium-server-standalone-3.1.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.1/selenium-server-standalone-3.1.0.jar; fi - - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.1.0.jar -log ./logs/selenium.log & + - if [ ! -f jar/selenium-server-standalone-3.4.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.4/selenium-server-standalone-3.4.0.jar; fi + - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.4.0.jar -log ./logs/selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" From 5f5d0fd96e984d31d80ec06e866ff126dfce496e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 5 Aug 2017 01:40:55 +0200 Subject: [PATCH 169/600] Add MS Edge build on SauceLabs --- .travis.yml | 13 +++++- tests/functional/FileUploadTest.php | 14 ++---- .../RemoteWebDriverFindElementTest.php | 2 +- tests/functional/RemoteWebElementTest.php | 10 ++++- tests/functional/WebDriverSelectTest.php | 44 +++++++++++++++++-- 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 68db86dfb..65e48e036 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,15 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + - php: 7.1 + env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="15.15063" PLATFORM="Windows 10" + before_script: + - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" + addons: + sauce_connect: true + jwt: + secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= # Codestyle check build - php: 7.1 @@ -82,7 +91,9 @@ before_script: - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" script: - - if [ -n "$SAUCELABS" ]; then EXTRA_PARAMS="--exclude-group exclude-saucelabs"; fi + - if [ -n "$SAUCELABS" ]; then EXCLUDE_GROUP+="exclude-saucelabs,"; fi + - if [ "$BROWSER_NAME" = "MicrosoftEdge" ]; then EXCLUDE_GROUP+="exclude-edge,"; fi + - if [ -n "$EXCLUDE_GROUP" ]; then EXTRA_PARAMS+=" --exclude-group $EXCLUDE_GROUP"; fi - ./vendor/bin/phpunit --coverage-clover ./logs/coverage-clover.xml $EXTRA_PARAMS after_script: diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index ef6cf1bb2..e88139953 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -23,6 +23,10 @@ */ class FileUploadTest extends WebDriverTestCase { + /** + * @group exclude-edge + * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6052385/ + */ public function testShouldUploadAFile() { $this->driver->get($this->getTestPageUrl('upload.html')); @@ -50,16 +54,6 @@ public function testShouldUploadAFile() $this->assertSame('10', $uploadedFileSize); } - public function xtestUselessFileDetectorSendKeys() - { - $this->driver->get($this->getTestPageUrl('upload.html')); - - $file_input = $this->driver->findElement(WebDriverBy::id('upload')); - $file_input->sendKeys($this->getTestFilePath()); - - $this->assertEquals($this->getTestFilePath(), $file_input->getAttribute('value')); - } - private function getTestFilePath() { return __DIR__ . '/Fixtures/FileUploadTestFile.txt'; diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 808763bad..004a554b8 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -28,7 +28,7 @@ public function testShouldThrowExceptionOfElementCannotBeFound() { $this->driver->get($this->getTestPageUrl('index.html')); - $this->setExpectedException(NoSuchElementException::class, 'Unable to locate element'); + $this->setExpectedException(NoSuchElementException::class); $this->driver->findElement(WebDriverBy::id('not_existing')); } diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 26d13f6e2..643e2a336 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -22,6 +22,8 @@ class RemoteWebElementTest extends WebDriverTestCase { /** * @covers ::getText + * @group exclude-edge + * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/5569343/ */ public function testShouldGetText() { @@ -90,8 +92,11 @@ public function testShouldGetCssValue() $this->assertSame('solid', $elementWithBorder->getCSSValue('border-left-style')); $this->assertSame('none', $elementWithoutBorder->getCSSValue('border-left-style')); - $this->assertSame('rgba(0, 0, 0, 1)', $elementWithBorder->getCSSValue('border-left-color')); - $this->assertSame('rgba(0, 0, 0, 1)', $elementWithoutBorder->getCSSValue('border-left-color')); + // Browser could report color in either rgb (like MS Edge) or rgba (like everyone else) + $this->assertRegExp( + '/rgba?\(0, 0, 0(, 1)?\)/', + $elementWithBorder->getCSSValue('border-left-color') + ); } /** @@ -206,6 +211,7 @@ public function testShouldSelectedInputsOrOptions() /** * @covers ::submit + * @group exclude-edge */ public function testShouldSubmitFormBySubmitEventOnForm() { diff --git a/tests/functional/WebDriverSelectTest.php b/tests/functional/WebDriverSelectTest.php index ac32cbca7..33ebe38f9 100644 --- a/tests/functional/WebDriverSelectTest.php +++ b/tests/functional/WebDriverSelectTest.php @@ -129,6 +129,10 @@ public function testShouldSelectOptionOfSimpleSelectByIndex() $this->assertSame('fourth', $select->getFirstSelectedOption()->getAttribute('value')); } + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ public function testShouldSelectOptionOfMultipleSelectByIndex() { $select = $this->getWebDriverSelectForMultipleSelect(); @@ -171,6 +175,10 @@ public function testShouldSelectOptionOfSimpleSelectByValue() $this->assertSame('fourth', $select->getFirstSelectedOption()->getAttribute('value')); } + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ public function testShouldSelectOptionOfMultipleSelectByValue() { $select = $this->getWebDriverSelectForMultipleSelect(); @@ -213,6 +221,10 @@ public function testShouldSelectOptionOfSimpleSelectByVisibleText() $this->assertSame('fifth', $select->getFirstSelectedOption()->getAttribute('value')); } + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ public function testShouldSelectOptionOfMultipleSelectByVisibleText() { $select = $this->getWebDriverSelectForMultipleSelect(); @@ -255,6 +267,10 @@ public function testShouldSelectOptionOfSimpleSelectByVisiblePartialText() $this->assertSame('fourth', $select->getFirstSelectedOption()->getAttribute('value')); } + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ public function testShouldSelectOptionOfMultipleSelectByVisiblePartialText() { $select = $this->getWebDriverSelectForMultipleSelect(); @@ -298,6 +314,10 @@ public function testShouldThrowExceptionWhenDeselectingOnSimpleSelect() $select->deselectAll(); } + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ public function testShouldDeselectAllOptionsOnMultipleSelect() { $select = $this->getWebDriverSelectForMultipleSelect(); @@ -312,7 +332,11 @@ public function testShouldDeselectAllOptionsOnMultipleSelect() $this->assertCount(0, $select->getAllSelectedOptions()); } - public function testShouldDeselectOptionByIndex() + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ + public function testShouldDeselectOptionOnMultipleSelectByIndex() { $select = $this->getWebDriverSelectForMultipleSelect(); $select->selectByValue('fourth'); // index 3 @@ -336,7 +360,11 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByIndex() $select->deselectByIndex(0); } - public function testShouldDeselectOptionByValue() + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ + public function testShouldDeselectOptionOnMultipleSelectByValue() { $select = $this->getWebDriverSelectForMultipleSelect(); $select->selectByValue('third'); @@ -360,7 +388,11 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByValue() $select->deselectByValue('first'); } - public function testShouldDeselectOptionByVisibleText() + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ + public function testShouldDeselectOptionOnMultipleSelectByVisibleText() { $select = $this->getWebDriverSelectForMultipleSelect(); $select->selectByValue('fourth'); // text 'Fourth with spaces inside' @@ -386,7 +418,11 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByVisibleText() $select->deselectByVisibleText('First'); } - public function testShouldDeselectOptionByVisiblePartialText() + /** + * @group exclude-edge + * https://connect.microsoft.com/IE/feedback/details/2020772/-microsoft-edge-webdriver-cannot-select-multiple-on-select-html-tag + */ + public function testShouldDeselectOptionOnMultipleSelectByVisiblePartialText() { $select = $this->getWebDriverSelectForMultipleSelect(); $select->selectByValue('fourth'); // text 'Fourth with spaces inside' From 735a6156617d62fe95ed20e6d038daa22b98e74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 5 Aug 2017 15:20:28 +0200 Subject: [PATCH 170/600] Extend connection timeout, because Edge is slow... --- tests/functional/RemoteWebDriverCreateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 95ff4851c..466e1601c 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -29,7 +29,7 @@ class RemoteWebDriverCreateTest extends WebDriverTestCase public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() { - $this->driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities, 10000, 13370); + $this->driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities, 30000, 33370); $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); From cb1f8bd54058ff3ded938e811d50e72e6c3a13ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 4 Aug 2017 22:20:51 +0200 Subject: [PATCH 171/600] Drop PHP 5.5 support --- .travis.yml | 1 - CHANGELOG.md | 2 ++ lib/Support/Events/EventFiringWebDriver.php | 5 ++--- lib/Support/Events/EventFiringWebDriverNavigation.php | 5 ++--- lib/Support/Events/EventFiringWebElement.php | 6 +++--- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 65e48e036..9b2b5894e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ sudo: false dist: trusty php: - - 5.5 - 5.6 - 7.0 - 7.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index c7d018435..182aeda87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Changed +- Drop PHP 5.5 support, the minimal required version of PHP is now PHP 5.6. ## 1.4.1 - 2017-04-28 ### Fixed diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index ffac00e5c..c129ef015 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -396,15 +396,14 @@ protected function newElement(WebDriverElement $element) /** * @param mixed $method + * @param mixed $arguments,... */ - protected function dispatch($method) + protected function dispatch($method, ...$arguments) { if (!$this->dispatcher) { return; } - $arguments = func_get_args(); - unset($arguments[0]); $this->dispatcher->dispatch($method, $arguments); } diff --git a/lib/Support/Events/EventFiringWebDriverNavigation.php b/lib/Support/Events/EventFiringWebDriverNavigation.php index 5aeaf510b..0008ebbdc 100644 --- a/lib/Support/Events/EventFiringWebDriverNavigation.php +++ b/lib/Support/Events/EventFiringWebDriverNavigation.php @@ -149,15 +149,14 @@ public function to($url) /** * @param mixed $method + * @param mixed $arguments,... */ - protected function dispatch($method) + protected function dispatch($method, ...$arguments) { if (!$this->dispatcher) { return; } - $arguments = func_get_args(); - unset($arguments[0]); $this->dispatcher->dispatch($method, $arguments); } diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index f932b20a3..099bb3573 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -392,14 +392,14 @@ protected function dispatchOnException(WebDriverException $exception) /** * @param mixed $method + * @param mixed $arguments,... */ - protected function dispatch($method) + protected function dispatch($method, ...$arguments) { if (!$this->dispatcher) { return; } - $arguments = func_get_args(); - unset($arguments[0]); + $this->dispatcher->dispatch($method, $arguments); } From 1c5e7f08d670f1ad921d3425903f852204fd8977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 25 Aug 2017 20:29:48 +0200 Subject: [PATCH 172/600] Extend connection timeout further more to make SauceLabs tests hopefully more stable --- tests/functional/RemoteWebDriverCreateTest.php | 18 ++++++++++++++---- tests/functional/WebDriverTestCase.php | 11 ++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 466e1601c..3140b26b0 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -29,7 +29,12 @@ class RemoteWebDriverCreateTest extends WebDriverTestCase public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() { - $this->driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities, 30000, 33370); + $this->driver = RemoteWebDriver::create( + $this->serverUrl, + $this->desiredCapabilities, + $this->connectionTimeout, + $this->requestTimeout + ); $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); @@ -51,8 +56,8 @@ public function testShouldCreateWebDriverWithRequiredCapabilities() $this->driver = RemoteWebDriver::create( $this->serverUrl, $this->desiredCapabilities, - null, - null, + $this->connectionTimeout, + $this->requestTimeout, null, null, $requiredCapabilities @@ -64,7 +69,12 @@ public function testShouldCreateWebDriverWithRequiredCapabilities() public function testShouldCreateInstanceFromExistingSessionId() { // Create driver instance and load page "index.html" - $originalDriver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities); + $originalDriver = RemoteWebDriver::create( + $this->serverUrl, + $this->desiredCapabilities, + $this->connectionTimeout, + $this->requestTimeout + ); $originalDriver->get($this->getTestPageUrl('index.html')); $this->assertContains('/index.html', $originalDriver->getCurrentURL()); diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 0c11e3fb8..77a98f884 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -34,6 +34,10 @@ class WebDriverTestCase extends \PHPUnit_Framework_TestCase protected $serverUrl = 'http://localhost:4444/wd/hub'; /** @var DesiredCapabilities */ protected $desiredCapabilities; + /** @var int */ + protected $connectionTimeout = 60000; + /** @var int */ + protected $requestTimeout = 60000; protected function setUp() { @@ -58,7 +62,12 @@ protected function setUp() } if ($this->createWebDriver) { - $this->driver = RemoteWebDriver::create($this->serverUrl, $this->desiredCapabilities); + $this->driver = RemoteWebDriver::create( + $this->serverUrl, + $this->desiredCapabilities, + $this->connectionTimeout, + $this->requestTimeout + ); } } From 3581da1e816335f09b3508c6d64baf2a91512cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 31 Aug 2017 17:13:20 +0200 Subject: [PATCH 173/600] Use only PHPUnit 5.4+, drop deprecated calls --- composer.json | 4 +- .../RemoteWebDriverFindElementTest.php | 2 +- tests/functional/WebDriverAlertTest.php | 2 +- tests/functional/WebDriverSelectTest.php | 66 +++++++------------ tests/functional/WebDriverTimeoutsTest.php | 2 +- tests/unit/CookieTest.php | 3 +- tests/unit/WebDriverOptionsTest.php | 6 +- 7 files changed, 31 insertions(+), 54 deletions(-) diff --git a/composer.json b/composer.json index 0a87cb3ed..cbf3155a9 100644 --- a/composer.json +++ b/composer.json @@ -11,13 +11,13 @@ "source": "https://github.com/facebook/php-webdriver" }, "require": { - "php": "^5.5 || ~7.0", + "php": "^5.6 || ~7.0", "symfony/process": "^2.8 || ^3.1", "ext-curl": "*", "ext-zip": "*" }, "require-dev": { - "phpunit/phpunit": "4.6.* || ~5.0", + "phpunit/phpunit": "^5.4", "friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 004a554b8..106d5d90f 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -28,7 +28,7 @@ public function testShouldThrowExceptionOfElementCannotBeFound() { $this->driver->get($this->getTestPageUrl('index.html')); - $this->setExpectedException(NoSuchElementException::class); + $this->expectException(NoSuchElementException::class); $this->driver->findElement(WebDriverBy::id('not_existing')); } diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index 61126b9bd..08d8ef73c 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -48,7 +48,7 @@ public function testShouldAcceptAlert() $this->driver->switchTo()->alert()->accept(); - $this->setExpectedException(NoAlertOpenException::class); + $this->expectException(NoAlertOpenException::class); $this->driver->switchTo()->alert()->accept(); } diff --git a/tests/functional/WebDriverSelectTest.php b/tests/functional/WebDriverSelectTest.php index 33ebe38f9..9cd6cf250 100644 --- a/tests/functional/WebDriverSelectTest.php +++ b/tests/functional/WebDriverSelectTest.php @@ -51,10 +51,8 @@ public function testShouldThrowExceptionWhenNotInstantiatedOnSelectElement() { $notSelectElement = $this->driver->findElement(WebDriverBy::cssSelector('textarea')); - $this->setExpectedException( - UnexpectedTagNameException::class, - 'Element should have been "select" but was "textarea"' - ); + $this->expectException(UnexpectedTagNameException::class); + $this->expectExceptionMessage('Element should have been "select" but was "textarea"'); new WebDriverSelect($notSelectElement); } @@ -109,10 +107,8 @@ public function testShouldThrowExceptionIfThereIsNoFirstSelectedOptionOfMultiple { $select = $this->getWebDriverSelectForMultipleSelect(); - $this->setExpectedException( - NoSuchElementException::class, - 'No options are selected' - ); + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('No options are selected'); $select->getFirstSelectedOption(); } @@ -155,10 +151,8 @@ public function testShouldThrowExceptionIfThereIsNoOptionIndexToSelect() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - NoSuchElementException::class, - 'Cannot locate option with index: 1337' - ); + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate option with index: 1337'); $select->selectByIndex(1337); } @@ -201,10 +195,8 @@ public function testShouldThrowExceptionIfThereIsNoOptionValueToSelect() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - NoSuchElementException::class, - 'Cannot locate option with value: 1337' - ); + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate option with value: 1337'); $select->selectByValue(1337); } @@ -247,10 +239,8 @@ public function testShouldThrowExceptionIfThereIsNoOptionVisibleTextToSelect() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - NoSuchElementException::class, - 'Cannot locate option with text: second' - ); + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate option with text: second'); $select->selectByVisibleText('second'); // the option is "This is second option" } @@ -296,10 +286,8 @@ public function testShouldThrowExceptionIfThereIsNoOptionVisiblePartialTextToSel { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - NoSuchElementException::class, - 'Cannot locate option with text: Not existing option' - ); + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate option with text: Not existing option'); $select->selectByVisiblePartialText('Not existing option'); } @@ -307,10 +295,8 @@ public function testShouldThrowExceptionWhenDeselectingOnSimpleSelect() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - UnsupportedOperationException::class, - 'You may only deselect all options of a multi-select' - ); + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You may only deselect all options of a multi-select'); $select->deselectAll(); } @@ -353,10 +339,8 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByIndex() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - UnsupportedOperationException::class, - 'You may only deselect options of a multi-select' - ); + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You may only deselect options of a multi-select'); $select->deselectByIndex(0); } @@ -381,10 +365,8 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByValue() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - UnsupportedOperationException::class, - 'You may only deselect options of a multi-select' - ); + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You may only deselect options of a multi-select'); $select->deselectByValue('first'); } @@ -411,10 +393,8 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByVisibleText() { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - UnsupportedOperationException::class, - 'You may only deselect options of a multi-select' - ); + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You may only deselect options of a multi-select'); $select->deselectByVisibleText('First'); } @@ -447,10 +427,8 @@ public function testShouldThrowExceptionIfDeselectingSimpleSelectByVisiblePartia { $select = $this->getWebDriverSelectForSimpleSelect(); - $this->setExpectedException( - UnsupportedOperationException::class, - 'You may only deselect options of a multi-select' - ); + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You may only deselect options of a multi-select'); $select->deselectByVisiblePartialText('First'); } diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index 51be6e13a..47edc886d 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -30,7 +30,7 @@ public function testShouldFailGettingDelayedElementWithoutWait() { $this->driver->get($this->getTestPageUrl('delayed_element.html')); - $this->setExpectedException(NoSuchElementException::class); + $this->expectException(NoSuchElementException::class); $this->driver->findElement(WebDriverBy::id('delayed')); } diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 0742a0789..ccf2a1e6f 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -146,7 +146,8 @@ public function testShouldBeCreatableFromAnArrayWithAllValues() public function testShouldValidateCookie($name, $value, $domain, $expectedMessage) { if ($expectedMessage) { - $this->setExpectedException(\InvalidArgumentException::class, $expectedMessage); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage($expectedMessage); } $cookie = new Cookie($name, $value); diff --git a/tests/unit/WebDriverOptionsTest.php b/tests/unit/WebDriverOptionsTest.php index 5e335854f..8bc47b96f 100644 --- a/tests/unit/WebDriverOptionsTest.php +++ b/tests/unit/WebDriverOptionsTest.php @@ -88,10 +88,8 @@ public function testShouldNotAllowToCreateCookieFromDifferentObjectThanCookie() $options = new WebDriverOptions($this->executor); - $this->setExpectedException( - \InvalidArgumentException::class, - 'Cookie must be set from instance of Cookie class or from array.' - ); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cookie must be set from instance of Cookie class or from array.'); $options->addCookie($notCookie); } From 11b1d4dcf40a0b382acb9322358cea2d97679d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 31 Aug 2017 16:47:09 +0200 Subject: [PATCH 174/600] Add functional tests for findElement for child elements --- .../RemoteWebDriverFindElementTest.php | 4 +- tests/functional/RemoteWebElementTest.php | 52 +++++++++++++++++++ tests/functional/web/index.html | 5 ++ tests/unit/Remote/RemoteWebElementTest.php | 36 +++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 tests/unit/Remote/RemoteWebElementTest.php diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 106d5d90f..46affc025 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -24,7 +24,7 @@ */ class RemoteWebDriverFindElementTest extends WebDriverTestCase { - public function testShouldThrowExceptionOfElementCannotBeFound() + public function testShouldThrowExceptionIfElementCannotBeFound() { $this->driver->get($this->getTestPageUrl('index.html')); @@ -58,7 +58,7 @@ public function testShouldFindMultipleElements() $elements = $this->driver->findElements(WebDriverBy::cssSelector('ul > li')); $this->assertInternalType('array', $elements); - $this->assertCount(3, $elements); + $this->assertCount(5, $elements); $this->assertContainsOnlyInstancesOf(RemoteWebElement::class, $elements); } } diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 643e2a336..51f414a93 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -15,6 +15,9 @@ namespace Facebook\WebDriver; +use Facebook\WebDriver\Exception\NoSuchElementException; +use Facebook\WebDriver\Remote\RemoteWebElement; + /** * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebElement */ @@ -282,4 +285,53 @@ public function testShouldCompareEqualsElement() $this->assertFalse($firstElement->equals($differentElement)); $this->assertFalse($differentElement->equals($againTheFirstElement)); } + + /** + * @covers ::findElement + */ + public function testShouldThrowExceptionIfChildElementCannotBeFound() + { + $this->driver->get($this->getTestPageUrl('index.html')); + $element = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); + + $this->expectException(NoSuchElementException::class); + $element->findElement(WebDriverBy::id('not_existing')); + } + + public function testShouldFindChildElementIfExistsOnAPage() + { + $this->driver->get($this->getTestPageUrl('index.html')); + $element = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); + + $childElement = $element->findElement(WebDriverBy::cssSelector('li')); + + $this->assertInstanceOf(RemoteWebElement::class, $childElement); + $this->assertSame('li', $childElement->getTagName()); + $this->assertSame('First', $childElement->getText()); + } + + public function testShouldReturnEmptyArrayIfChildElementsCannotBeFound() + { + $this->driver->get($this->getTestPageUrl('index.html')); + $element = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); + + $childElements = $element->findElements(WebDriverBy::cssSelector('not_existing')); + + $this->assertInternalType('array', $childElements); + $this->assertCount(0, $childElements); + } + + public function testShouldFindMultipleChildElements() + { + $this->driver->get($this->getTestPageUrl('index.html')); + $element = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); + + $allElements = $this->driver->findElements(WebDriverBy::cssSelector('li')); + $childElements = $element->findElements(WebDriverBy::cssSelector('li')); + + $this->assertInternalType('array', $childElements); + $this->assertCount(5, $allElements); // there should be 5
  • elements on page + $this->assertCount(3, $childElements); // but we should find only subelements of one
      + $this->assertContainsOnlyInstancesOf(RemoteWebElement::class, $childElements); + } } diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index 8e314f798..1a92f255e 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -30,6 +30,11 @@

      Welcome to the facebook/php-webdriver testing page.

    • Third
    +
      +
    • Foo
    • +
    • Bar
    • +
    +

    Foo bar text

    Multiple spaces are diff --git a/tests/unit/Remote/RemoteWebElementTest.php b/tests/unit/Remote/RemoteWebElementTest.php new file mode 100644 index 000000000..45c057751 --- /dev/null +++ b/tests/unit/Remote/RemoteWebElementTest.php @@ -0,0 +1,36 @@ +createMock(RemoteExecuteMethod::class); + $element = new RemoteWebElement($executeMethod, 333); + + $this->assertSame(333, $element->getID()); + } +} From e8ebc12da32a019612e8874c7e81a884535d1894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 5 Sep 2017 23:37:38 +0200 Subject: [PATCH 175/600] Improve code-coverage settings --- lib/Firefox/FirefoxDriver.php | 3 +++ lib/Firefox/FirefoxPreferences.php | 2 ++ lib/Remote/DriverCommand.php | 2 ++ lib/Remote/WebDriverBrowserType.php | 4 +++- lib/Remote/WebDriverCapabilityType.php | 2 ++ lib/WebDriverPlatform.php | 2 ++ tests/functional/RemoteWebDriverTest.php | 6 ++---- tests/functional/WebDriverTimeoutsTest.php | 2 ++ 8 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/Firefox/FirefoxDriver.php b/lib/Firefox/FirefoxDriver.php index 9e0751238..f2883e642 100644 --- a/lib/Firefox/FirefoxDriver.php +++ b/lib/Firefox/FirefoxDriver.php @@ -15,6 +15,9 @@ namespace Facebook\WebDriver\Firefox; +/** + * @codeCoverageIgnore + */ class FirefoxDriver { const PROFILE = 'firefox_profile'; diff --git a/lib/Firefox/FirefoxPreferences.php b/lib/Firefox/FirefoxPreferences.php index b869a2667..be1199c24 100644 --- a/lib/Firefox/FirefoxPreferences.php +++ b/lib/Firefox/FirefoxPreferences.php @@ -18,6 +18,8 @@ /** * Constants of common Firefox profile preferences (about:config values). * @see http://kb.mozillazine.org/Firefox_:_FAQs_:_About:config_Entries + * + * @codeCoverageIgnore */ class FirefoxPreferences { diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index 1b86c71c6..c69052030 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -17,6 +17,8 @@ /** * This list of command defined in the WebDriver json wire protocol. + * + * @codeCoverageIgnore */ class DriverCommand { diff --git a/lib/Remote/WebDriverBrowserType.php b/lib/Remote/WebDriverBrowserType.php index 5dd61505e..53b6ab977 100644 --- a/lib/Remote/WebDriverBrowserType.php +++ b/lib/Remote/WebDriverBrowserType.php @@ -16,7 +16,9 @@ namespace Facebook\WebDriver\Remote; /** - * All the browsers supported by selenium + * All the browsers supported by selenium. + * + * @codeCoverageIgnore */ class WebDriverBrowserType { diff --git a/lib/Remote/WebDriverCapabilityType.php b/lib/Remote/WebDriverCapabilityType.php index 131b16561..c452e771c 100644 --- a/lib/Remote/WebDriverCapabilityType.php +++ b/lib/Remote/WebDriverCapabilityType.php @@ -17,6 +17,8 @@ /** * WebDriverCapabilityType contains all constants defined in the WebDriver Wire Protocol. + * + * @codeCoverageIgnore */ class WebDriverCapabilityType { diff --git a/lib/WebDriverPlatform.php b/lib/WebDriverPlatform.php index bb1923556..5609eb0b8 100644 --- a/lib/WebDriverPlatform.php +++ b/lib/WebDriverPlatform.php @@ -17,6 +17,8 @@ /** * The platforms supported by WebDriver. + * + * @codeCoverageIgnore */ class WebDriverPlatform { diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 7b60b69d7..006b17c7b 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -45,10 +45,7 @@ public function testShouldGetCurrentUrl() { $this->driver->get($this->getTestPageUrl('index.html')); - $this->assertContains( - '/index.html', - $this->driver->getCurrentURL() - ); + $this->assertStringEndsWith('/index.html', $this->driver->getCurrentURL()); } /** @@ -173,6 +170,7 @@ function(){document.getElementById("id_test").innerHTML = "Text changed by scrip /** * @covers ::executeAsyncScript + * @covers Facebook\WebDriver\WebDriverTimeouts::setScriptTimeout */ public function testShouldExecuteAsyncScriptAndWaitUntilItIsFinished() { diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index 47edc886d..808a494ab 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -36,6 +36,7 @@ public function testShouldFailGettingDelayedElementWithoutWait() /** * @covers ::implicitlyWait + * @covers ::__construct */ public function testShouldGetDelayedElementWithImplicitWait() { @@ -49,6 +50,7 @@ public function testShouldGetDelayedElementWithImplicitWait() /** * @covers ::pageLoadTimeout + * @covers ::__construct */ public function testShouldFailIfPageIsLoadingLongerThanPageLoadTimeout() { From 7672fe48b2c11784e71156108ae5b3568d31278c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 6 Sep 2017 01:18:38 +0200 Subject: [PATCH 176/600] Add functional tests for WebDriverNavigation --- lib/WebDriverNavigation.php | 1 + tests/functional/WebDriverNavigationTest.php | 85 ++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 tests/functional/WebDriverNavigationTest.php diff --git a/lib/WebDriverNavigation.php b/lib/WebDriverNavigation.php index ccc8cee30..6de59b035 100644 --- a/lib/WebDriverNavigation.php +++ b/lib/WebDriverNavigation.php @@ -75,6 +75,7 @@ public function refresh() /** * Navigate to the given URL. * + * @see WebDriver::get() * @param string $url * @return WebDriverNavigation The instance. */ diff --git a/tests/functional/WebDriverNavigationTest.php b/tests/functional/WebDriverNavigationTest.php new file mode 100644 index 000000000..4f7dba252 --- /dev/null +++ b/tests/functional/WebDriverNavigationTest.php @@ -0,0 +1,85 @@ +driver->navigate()->to($this->getTestPageUrl('index.html')); + + $this->assertStringEndsWith('/index.html', $this->driver->getCurrentURL()); + } + + /** + * @covers ::back + * @covers ::forward + */ + public function testShouldNavigateBackAndForward() + { + $this->driver->get($this->getTestPageUrl('index.html')); + $linkElement = $this->driver->findElement(WebDriverBy::id('a-form')); + + $linkElement->click(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::urlContains('form.html') + ); + + $this->driver->navigate()->back(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::urlContains('index.html') + ); + + $this->driver->navigate()->forward(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::urlContains('form.html') + ); + } + + /** + * @covers ::refresh + */ + public function testShouldRefreshPage() + { + $this->driver->get($this->getTestPageUrl('index.html')); + + // Change input element content, to make sure it was refreshed (=> cleared to original value) + $inputElement = $this->driver->findElement(WebDriverBy::name('test_name')); + $inputElementOriginalValue = $inputElement->getAttribute('value'); + $inputElement->clear()->sendKeys('New value'); + $this->assertSame('New value', $inputElement->getAttribute('value')); + + $this->driver->navigate()->refresh(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::stalenessOf($inputElement) + ); + + $inputElementAfterRefresh = $this->driver->findElement(WebDriverBy::name('test_name')); + + $this->assertSame($inputElementOriginalValue, $inputElementAfterRefresh->getAttribute('value')); + } +} From 61f547414294b8188e149594486d1a91d0f7c8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 17 Sep 2017 09:54:20 +0200 Subject: [PATCH 177/600] Add symfony/var-dumper dev dependency for easier development --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index cbf3155a9..8eff450f7 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ "friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", - "satooshi/php-coveralls": "^1.0" + "satooshi/php-coveralls": "^1.0", + "symfony/var-dumper": "^3.3" }, "autoload": { "psr-4": { From 944c76eb61403ee9479a58285c4cd2abae00526e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 13 Oct 2017 23:59:03 +0200 Subject: [PATCH 178/600] Update readme - passThrough mode, mention Java 8 is required for Selenium server --- README.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cfdf0bc3b..5b331d349 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,14 @@ Then install the library: All you need as the server for this client is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html -Download and run that file, replacing # with the current server version. +Download and run that file, replacing # with the current server version. Keep in mind you must have Java 8+ installed to start this command. java -jar selenium-server-standalone-#.jar +When using Selenium server 3.5 and newer with some remote end clients (eg. Firefox with Geckodriver), you MUST disable so called "pass-through" mode, so that remote browser's protocol is translated to the protocol supported by php-webdriver (see [issue #469](https://github.com/facebook/php-webdriver/issues/469)): + + java -jar selenium-server-standalone-#.jar -enablePassThrough false + Then when you create a session, be sure to pass the url to where your server is running. ```php @@ -50,19 +54,23 @@ Then when you create a session, be sure to pass the url to where your server is $host = 'http://localhost:4444/wd/hub'; // this is the default ``` -* Launch Firefox: +##### Launch Firefox + +Make sure to have latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases) installed. + +```php +$driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); +``` - ```php - $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); - ``` +##### Launch Chrome -* Launch Chrome: +Make sure to have latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) installed. - ```php - $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); - ``` +```php +$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); +``` -You can also customize the desired capabilities: +##### You can also customize the desired capabilities ```php $desired_capabilities = DesiredCapabilities::firefox(); From 4c2710810148b8c266ced5aad55ac4ad70a36aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 14 Oct 2017 03:50:51 +0200 Subject: [PATCH 179/600] Add functional tests for basic actions (click, double click etc.) --- lib/Interactions/WebDriverCompositeAction.php | 2 +- tests/functional/WebDriverActionsTest.php | 140 ++++++++++++++++++ tests/functional/web/events.html | 86 +++++++++++ tests/functional/web/index.html | 2 + 4 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 tests/functional/WebDriverActionsTest.php create mode 100644 tests/functional/web/events.html diff --git a/lib/Interactions/WebDriverCompositeAction.php b/lib/Interactions/WebDriverCompositeAction.php index 75a4837e1..d4ca94c5d 100644 --- a/lib/Interactions/WebDriverCompositeAction.php +++ b/lib/Interactions/WebDriverCompositeAction.php @@ -51,7 +51,7 @@ public function getNumberOfActions() } /** - * Perform the seqeunce of actions. + * Perform the sequence of actions. */ public function perform() { diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php new file mode 100644 index 000000000..173f7794c --- /dev/null +++ b/tests/functional/WebDriverActionsTest.php @@ -0,0 +1,140 @@ +driver->get($this->getTestPageUrl('events.html')); + } + + /** + * @covers ::__construct + * @covers ::click + * @covers ::perform + */ + public function testShouldClickOnElement() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $element = $this->driver->findElement(WebDriverBy::id('item-1')); + + $this->driver->action() + ->click($element) + ->perform(); + + $this->assertSame( + ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1'], + $this->retrieveLoggedEvents() + ); + } + + /** + * @covers ::__construct + * @covers ::clickAndHold + * @covers ::release + * @covers ::perform + */ + public function testShouldClickAndHoldOnElementAndRelease() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $element = $this->driver->findElement(WebDriverBy::id('item-1')); + + $this->driver->action() + ->clickAndHold($element) + ->release() + ->perform(); + + $this->assertSame( + ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1'], + $this->retrieveLoggedEvents() + ); + } + + /** + * @covers ::__construct + * @covers ::contextClick + * @covers ::perform + */ + public function testShouldContextClickOnElement() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::MICROSOFT_EDGE) { + $this->markTestSkipped('Getting stuck in EdgeDriver'); + } + + $element = $this->driver->findElement(WebDriverBy::id('item-2')); + + $this->driver->action() + ->contextClick($element) + ->perform(); + + $loggedEvents = $this->retrieveLoggedEvents(); + + $this->assertContains('mousedown item-2', $loggedEvents); + $this->assertContains('mouseup item-2', $loggedEvents); + $this->assertContains('contextmenu item-2', $loggedEvents); + } + + /** + * @covers ::__construct + * @covers ::doubleClick + * @covers ::perform + */ + public function testShouldDoubleClickOnElement() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $element = $this->driver->findElement(WebDriverBy::id('item-3')); + + $this->driver->action() + ->doubleClick($element) + ->perform(); + + $this->assertSame( + ['mouseover item-3', 'mousedown item-3', 'mouseup item-3', 'click item-3', 'dblclick item-3'], + $this->retrieveLoggedEvents() + ); + } + + /** + * @return array + */ + private function retrieveLoggedEvents() + { + $logElement = $this->driver->findElement(WebDriverBy::id('log')); + + return explode("\n", $logElement->getText()); + } +} diff --git a/tests/functional/web/events.html b/tests/functional/web/events.html new file mode 100644 index 000000000..e915a89a0 --- /dev/null +++ b/tests/functional/web/events.html @@ -0,0 +1,86 @@ + + + + + Events + + + + +

      + +
    + +
      +
    • First item
    • +
    • Second item
    • +
    • Third item
    • +
    + +
    
    +
    +
    +
    +
    +
    diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html
    index 1a92f255e..cf5b9c6c1 100644
    --- a/tests/functional/web/index.html
    +++ b/tests/functional/web/index.html
    @@ -18,6 +18,8 @@ 

    Welcome to the facebook/php-webdriver testing page.

    Slow loading page | Javascript alerts + | + Events

    Test by ID

    Test by Class

    From cae27962e3b1e4fae70c951769c00204bd927eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 25 Oct 2017 23:05:52 +0200 Subject: [PATCH 180/600] Add tests for ChromeDriverService and ChromeDriver --- .travis.yml | 12 ++- .../Chrome/ChromeDriverServiceTest.php | 82 +++++++++++++++++++ tests/functional/Chrome/ChromeDriverTest.php | 60 ++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 tests/functional/Chrome/ChromeDriverServiceTest.php create mode 100644 tests/functional/Chrome/ChromeDriverTest.php diff --git a/.travis.yml b/.travis.yml index 9b2b5894e..7484f1cfc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,13 @@ matrix: # Build with lowest possible dependencies - php: 7.1 - env: dependencies="--prefer-lowest" + env: DEPENDENCIES="--prefer-lowest" + + # Chrome on Travis build with lowest possible dependencies + - php: 7.1 + env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" DEPENDENCIES="--prefer-lowest" + addons: + chrome: beta # Saucelabs builds - php: 7.1 @@ -77,11 +83,11 @@ before_install: - travis_retry composer self-update install: - - travis_retry composer update --no-interaction $dependencies + - travis_retry composer update --no-interaction $DEPENDENCIES before_script: - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=./chromedriver/chromedriver; fi + - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.4.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.4/selenium-server-standalone-3.4.0.jar; fi - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.4.0.jar -log ./logs/selenium.log & diff --git a/tests/functional/Chrome/ChromeDriverServiceTest.php b/tests/functional/Chrome/ChromeDriverServiceTest.php new file mode 100644 index 000000000..6f6073fda --- /dev/null +++ b/tests/functional/Chrome/ChromeDriverServiceTest.php @@ -0,0 +1,82 @@ +markTestSkipped('ChromeDriverServiceTest is run only when running against local chrome'); + } + } + + public function testShouldStartAndStopServiceCreatedUsingShortcutConstructor() + { + // The createDefaultService() method expect path to the executable to be present in the environment variable + putenv(ChromeDriverService::CHROME_DRIVER_EXE_PROPERTY . '=' . getenv('CHROMEDRIVER_PATH')); + + $driverService = ChromeDriverService::createDefaultService(); + + $this->assertSame('http://localhost:9515/', $driverService->getURL()); + + $this->assertInstanceOf(ChromeDriverService::class, $driverService->start()); + $this->assertTrue($driverService->isRunning()); + + $this->assertInstanceOf(ChromeDriverService::class, $driverService->start()); + + $this->assertInstanceOf(ChromeDriverService::class, $driverService->stop()); + $this->assertFalse($driverService->isRunning()); + + $this->assertInstanceOf(ChromeDriverService::class, $driverService->stop()); + } + + public function testShouldStartAndStopServiceCreatedUsingDefaultConstructor() + { + $driverService = new ChromeDriverService(getenv('CHROMEDRIVER_PATH'), 9515, ['--port=9515']); + + $this->assertSame('http://localhost:9515/', $driverService->getURL()); + + $driverService->start(); + $this->assertTrue($driverService->isRunning()); + + $driverService->stop(); + $this->assertFalse($driverService->isRunning()); + } + + public function testShouldThrowExceptionIfExecutableCannotBeFound() + { + putenv(ChromeDriverService::CHROME_DRIVER_EXE_PROPERTY . '=/not/existing'); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('\'/not/existing\' is not a file.'); + ChromeDriverService::createDefaultService(); + } + + public function testShouldThrowExceptionIfExecutableIsNotExecutable() + { + putenv(ChromeDriverService::CHROME_DRIVER_EXE_PROPERTY . '=' . __FILE__); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('is not executable'); + ChromeDriverService::createDefaultService(); + } +} diff --git a/tests/functional/Chrome/ChromeDriverTest.php b/tests/functional/Chrome/ChromeDriverTest.php new file mode 100644 index 000000000..f3567d9d7 --- /dev/null +++ b/tests/functional/Chrome/ChromeDriverTest.php @@ -0,0 +1,60 @@ +markTestSkipped('ChromeDriverServiceTest is run only when running against local chrome'); + } + } + + protected function tearDown() + { + if ($this->driver instanceof RemoteWebDriver && $this->driver->getCommandExecutor() !== null) { + $this->driver->quit(); + } + } + + public function testShouldStartChromeDriver() + { + // The createDefaultService() method expect path to the executable to be present in the environment variable + putenv(ChromeDriverService::CHROME_DRIVER_EXE_PROPERTY . '=' . getenv('CHROMEDRIVER_PATH')); + + $this->driver = ChromeDriver::start(); + + $this->assertInstanceOf(ChromeDriver::class, $this->driver); + $this->assertInstanceOf(DriverCommandExecutor::class, $this->driver->getCommandExecutor()); + + $this->driver->get('http://localhost:8000/'); + + $this->assertSame('http://localhost:8000/', $this->driver->getCurrentURL()); + + $this->driver->quit(); + } +} From 2b1d15359f88ea246d4a18f5dda4cbdeec48eb73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 26 Oct 2017 10:14:17 +0200 Subject: [PATCH 181/600] Bump sebastian/environment version to fix code-coverage in lowest dependencies build See https://github.com/sebastianbergmann/phpunit/issues/1976 --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8eff450f7..6203b6238 100644 --- a/composer.json +++ b/composer.json @@ -18,10 +18,11 @@ }, "require-dev": { "phpunit/phpunit": "^5.4", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", "friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", - "satooshi/php-coveralls": "^1.0", + "php-coveralls/php-coveralls": "^1.0.2", "symfony/var-dumper": "^3.3" }, "autoload": { From c85b872ba733b303ca363ecf27f87ae45a543b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 26 Oct 2017 15:17:50 +0200 Subject: [PATCH 182/600] Bump guzzle version to fix coveralls in lowest dependencies build --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 6203b6238..6b7685be9 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", "php-coveralls/php-coveralls": "^1.0.2", + "guzzle/guzzle": "^3.4.1", "symfony/var-dumper": "^3.3" }, "autoload": { From f6e0ad46640248112b636593d59db8032fa13c73 Mon Sep 17 00:00:00 2001 From: VolCh Date: Thu, 2 Nov 2017 19:07:27 +0200 Subject: [PATCH 183/600] Fix code style --- lib/WebDriverSelectInterface.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/WebDriverSelectInterface.php b/lib/WebDriverSelectInterface.php index bd4db90e4..030a783e9 100644 --- a/lib/WebDriverSelectInterface.php +++ b/lib/WebDriverSelectInterface.php @@ -1,4 +1,5 @@ Date: Fri, 3 Nov 2017 10:41:52 +0200 Subject: [PATCH 184/600] Fix code style --- lib/WebDriverDimension.php | 2 +- lib/WebDriverExpectedCondition.php | 4 ++-- lib/WebDriverPoint.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/WebDriverDimension.php b/lib/WebDriverDimension.php index 111a77821..308c1990f 100644 --- a/lib/WebDriverDimension.php +++ b/lib/WebDriverDimension.php @@ -65,7 +65,7 @@ public function getWidth() * @param WebDriverDimension $dimension The dimension to be compared with. * @return bool Whether the height and the width are the same as the instance. */ - public function equals(WebDriverDimension $dimension) + public function equals(self $dimension) { return $this->height === $dimension->getHeight() && $this->width === $dimension->getWidth(); } diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 347a5d28a..bce6bfee4 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -453,7 +453,7 @@ function () use ($element) { * @return WebDriverExpectedCondition Condition returns the return value of the getApply() of the given * condition. */ - public static function refreshed(WebDriverExpectedCondition $condition) + public static function refreshed(self $condition) { return new static( function (WebDriver $driver) use ($condition) { @@ -558,7 +558,7 @@ function (WebDriver $driver) use ($expectedNumberOfWindows) { * @param WebDriverExpectedCondition $condition The condition to be negated. * @return mixed The negation of the result of the given condition. */ - public static function not(WebDriverExpectedCondition $condition) + public static function not(self $condition) { return new static( function (WebDriver $driver) use ($condition) { diff --git a/lib/WebDriverPoint.php b/lib/WebDriverPoint.php index e12977b22..4e2dbd211 100644 --- a/lib/WebDriverPoint.php +++ b/lib/WebDriverPoint.php @@ -85,7 +85,7 @@ public function moveBy($x_offset, $y_offset) * @param WebDriverPoint $point The point to be compared with. * @return bool Whether the x and y coordinates are the same as the instance. */ - public function equals(WebDriverPoint $point) + public function equals(self $point) { return $this->x === $point->getX() && $this->y === $point->getY(); From 4eee996a85b6fee638f5f95990c95f8832a18755 Mon Sep 17 00:00:00 2001 From: Quentin Headen Date: Tue, 7 Nov 2017 04:37:32 +0000 Subject: [PATCH 185/600] Add WebDriverExpectedCondition::visibilityOfAnyElementsLocated --- CHANGELOG.md | 3 ++ lib/WebDriverExpectedCondition.php | 29 ++++++++++++++++++ tests/unit/WebDriverExpectedConditionTest.php | 30 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 182aeda87..c8b503b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Changed - Drop PHP 5.5 support, the minimal required version of PHP is now PHP 5.6. +### Added +- Added a visibilityOfAnyElementsLocated method to WebDriverExpectedCondition. + ## 1.4.1 - 2017-04-28 ### Fixed - Do not throw notice `Constant CURLOPT_CONNECTTIMEOUT_MS already defined`. diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index bce6bfee4..433ee1a3a 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -193,6 +193,35 @@ function (WebDriver $driver) use ($by) { ); } + /** + * An expectation for checking than at least one element in an array of elements is present on the + * DOM of a page and visible. + * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. + * + * @param WebDriverBy $by The located used to find the element. + * @return WebDriverExpectedCondition Condition returns the elements that are located and visible. + */ + public static function visibilityOfAnyElementLocated(WebDriverBy $by) + { + return new static( + function (WebDriver $driver) use ($by) { + $elements = $driver->findElements($by); + $visibleElements = []; + + foreach ($elements as $element) { + try { + if ($element->isDisplayed()) { + $visibleElements[] = $element; + } + } catch (StateElementReferenceException $e) { + } + } + + return count($visibleElements) > 0 ? $visibleElements : null; + } + ); + } + /** * An expectation for checking that an element, known to be present on the DOM of a page, is visible. * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index e786167a8..603829c02 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -185,6 +185,36 @@ public function testShouldDetectVisibilityOfElementLocatedCondition() $this->assertSame($element, $this->wait->until($condition)); } + public function testShouldDetectVisibilityOfAnyElementLocated() + { + $elementList = [ + $this->createRemoteWebElementMock(), + $this->createRemoteWebElementMock(), + $this->createRemoteWebElementMock(), + ]; + + $elementList[0]->expects($this->once()) + ->method('isDisplayed') + ->willReturn(false); + + $elementList[1]->expects($this->once()) + ->method('isDisplayed') + ->willReturn(true); + + $elementList[2]->expects($this->once()) + ->method('isDisplayed') + ->willReturn(true); + + $this->driverMock->expects($this->once()) + ->method('findElements') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($elementList); + + $condition = WebDriverExpectedCondition::visibilityOfAnyElementLocated(WebDriverBy::cssSelector('.foo')); + + $this->assertSame([$elementList[1], $elementList[2]], $this->wait->until($condition)); + } + public function testShouldDetectInvisibilityOfElementLocatedConditionOnNoSuchElementException() { $element = $this->createRemoteWebElementMock(); From 017b8d7daee5c070235b8c74d335180f2bd15aa2 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Sat, 4 Nov 2017 17:27:25 -0200 Subject: [PATCH 186/600] Use namespaces for PHPUnit forward compatiblitiy --- composer.json | 2 +- tests/functional/Chrome/ChromeDriverServiceTest.php | 4 +++- tests/functional/Chrome/ChromeDriverTest.php | 3 ++- tests/functional/ReportSauceLabsStatusListener.php | 3 ++- tests/functional/WebDriverTestCase.php | 3 ++- tests/unit/CookieTest.php | 4 +++- tests/unit/Exception/WebDriverExceptionTest.php | 4 +++- .../Internal/WebDriverButtonReleaseActionTest.php | 3 ++- tests/unit/Interactions/Internal/WebDriverClickActionTest.php | 3 ++- .../Interactions/Internal/WebDriverClickAndHoldActionTest.php | 3 ++- .../Interactions/Internal/WebDriverContextClickActionTest.php | 3 ++- tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php | 4 +++- .../Interactions/Internal/WebDriverDoubleClickActionTest.php | 3 ++- .../unit/Interactions/Internal/WebDriverKeyDownActionTest.php | 3 ++- tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php | 3 ++- .../Interactions/Internal/WebDriverMouseMoveActionTest.php | 3 ++- .../Internal/WebDriverMouseToOffsetActionTest.php | 3 ++- .../Interactions/Internal/WebDriverSendKeysActionTest.php | 3 ++- tests/unit/Remote/DesiredCapabilitiesTest.php | 3 ++- tests/unit/Remote/HttpCommandExecutorTest.php | 3 ++- tests/unit/Remote/RemoteWebDriverTest.php | 3 ++- tests/unit/Remote/RemoteWebElementTest.php | 4 +++- tests/unit/Remote/WebDriverCommandTest.php | 4 +++- tests/unit/Support/XPathEscaperTest.php | 4 +++- tests/unit/WebDriverExpectedConditionTest.php | 3 ++- tests/unit/WebDriverKeysTest.php | 4 +++- tests/unit/WebDriverOptionsTest.php | 3 ++- 27 files changed, 61 insertions(+), 27 deletions(-) diff --git a/composer.json b/composer.json index 6b7685be9..94b7f8a36 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "ext-zip": "*" }, "require-dev": { - "phpunit/phpunit": "^5.4", + "phpunit/phpunit": "^5.7", "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", "friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.6", diff --git a/tests/functional/Chrome/ChromeDriverServiceTest.php b/tests/functional/Chrome/ChromeDriverServiceTest.php index 6f6073fda..bc1a1b92f 100644 --- a/tests/functional/Chrome/ChromeDriverServiceTest.php +++ b/tests/functional/Chrome/ChromeDriverServiceTest.php @@ -15,12 +15,14 @@ namespace Facebook\WebDriver\Chrome; +use PHPUnit\Framework\TestCase; + /** * @group exclude-saucelabs * @covers Facebook\WebDriver\Chrome\ChromeDriverService * @covers Facebook\WebDriver\Remote\Service\DriverService */ -class ChromeDriverServiceTest extends \PHPUnit_Framework_TestCase +class ChromeDriverServiceTest extends TestCase { protected function setUp() { diff --git a/tests/functional/Chrome/ChromeDriverTest.php b/tests/functional/Chrome/ChromeDriverTest.php index f3567d9d7..476033839 100644 --- a/tests/functional/Chrome/ChromeDriverTest.php +++ b/tests/functional/Chrome/ChromeDriverTest.php @@ -17,12 +17,13 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\Service\DriverCommandExecutor; +use PHPUnit\Framework\TestCase; /** * @group exclude-saucelabs * @covers Facebook\WebDriver\Chrome\ChromeDriver */ -class ChromeDriverTest extends \PHPUnit_Framework_TestCase +class ChromeDriverTest extends TestCase { /** @var ChromeDriver */ protected $driver; diff --git a/tests/functional/ReportSauceLabsStatusListener.php b/tests/functional/ReportSauceLabsStatusListener.php index b88b1cdf7..f2a3c9f7d 100644 --- a/tests/functional/ReportSauceLabsStatusListener.php +++ b/tests/functional/ReportSauceLabsStatusListener.php @@ -16,8 +16,9 @@ namespace Facebook\WebDriver; use Facebook\WebDriver\Remote\RemoteWebDriver; +use PHPUnit\Framework\BaseTestListener; -class ReportSauceLabsStatusListener extends \PHPUnit_Framework_BaseTestListener +class ReportSauceLabsStatusListener extends BaseTestListener { public function endTest(\PHPUnit_Framework_Test $test, $time) { diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 77a98f884..4abaf7c03 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -20,11 +20,12 @@ use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\WebDriverBrowserType; +use PHPUnit\Framework\TestCase; /** * The base class for test cases. */ -class WebDriverTestCase extends \PHPUnit_Framework_TestCase +class WebDriverTestCase extends TestCase { /** @var RemoteWebDriver $driver */ public $driver; diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index ccf2a1e6f..5fc62fb6c 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -15,10 +15,12 @@ namespace Facebook\WebDriver; +use PHPUnit\Framework\TestCase; + /** * @covers Facebook\WebDriver\Cookie */ -class CookieTest extends \PHPUnit_Framework_TestCase +class CookieTest extends TestCase { public function testShouldSetAllProperties() { diff --git a/tests/unit/Exception/WebDriverExceptionTest.php b/tests/unit/Exception/WebDriverExceptionTest.php index 1dfd94fac..f9aadd207 100644 --- a/tests/unit/Exception/WebDriverExceptionTest.php +++ b/tests/unit/Exception/WebDriverExceptionTest.php @@ -15,7 +15,9 @@ namespace Facebook\WebDriver\Exception; -class WebDriverExceptionTest extends \PHPUnit_Framework_TestCase +use PHPUnit\Framework\TestCase; + +class WebDriverExceptionTest extends TestCase { public function testShouldStoreResultsOnInstantiation() { diff --git a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php index f2bb1b647..db8574a0b 100644 --- a/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverButtonReleaseActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverButtonReleaseActionTest extends \PHPUnit_Framework_TestCase +class WebDriverButtonReleaseActionTest extends TestCase { /** @var WebDriverButtonReleaseAction */ private $webDriverButtonReleaseAction; diff --git a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php index fdb868141..8041d7ae7 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverClickActionTest extends \PHPUnit_Framework_TestCase +class WebDriverClickActionTest extends TestCase { /** @var WebDriverClickAction */ private $webDriverClickAction; diff --git a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php index eb3f4bc6f..ebe933f8c 100644 --- a/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverClickAndHoldActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverClickAndHoldActionTest extends \PHPUnit_Framework_TestCase +class WebDriverClickAndHoldActionTest extends TestCase { /** @var WebDriverClickAndHoldAction */ private $webDriverClickAndHoldAction; diff --git a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php index e9162f239..67ca63e4c 100644 --- a/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverContextClickActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverContextClickActionTest extends \PHPUnit_Framework_TestCase +class WebDriverContextClickActionTest extends TestCase { /** @var WebDriverContextClickAction */ private $webDriverContextClickAction; diff --git a/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php b/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php index d782edf8c..209daa63f 100644 --- a/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php +++ b/tests/unit/Interactions/Internal/WebDriverCoordinatesTest.php @@ -15,7 +15,9 @@ namespace Facebook\WebDriver\Interactions\Internal; -class WebDriverCoordinatesTest extends \PHPUnit_Framework_TestCase +use PHPUnit\Framework\TestCase; + +class WebDriverCoordinatesTest extends TestCase { public function testConstruct() { diff --git a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php index acd74550f..86710d330 100644 --- a/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverDoubleClickActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverDoubleClickActionTest extends \PHPUnit_Framework_TestCase +class WebDriverDoubleClickActionTest extends TestCase { /** @var WebDriverDoubleClickAction */ private $webDriverDoubleClickAction; diff --git a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php index 267b58b3e..a03791fd9 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyDownActionTest.php @@ -18,8 +18,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverKeyboard; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverKeyDownActionTest extends \PHPUnit_Framework_TestCase +class WebDriverKeyDownActionTest extends TestCase { /** @var WebDriverKeyDownAction */ private $webDriverKeyDownAction; diff --git a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php index 970a35b0f..7ebc17ac0 100644 --- a/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverKeyUpActionTest.php @@ -18,8 +18,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverKeyboard; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverKeyUpActionTest extends \PHPUnit_Framework_TestCase +class WebDriverKeyUpActionTest extends TestCase { /** @var WebDriverKeyUpAction */ private $webDriverKeyUpAction; diff --git a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php index 565530ad8..584231f9d 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseMoveActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverMouseMoveActionTest extends \PHPUnit_Framework_TestCase +class WebDriverMouseMoveActionTest extends TestCase { /** @var WebDriverMouseMoveAction */ private $webDriverMouseMoveAction; diff --git a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php index d2d5286a1..a055c746d 100644 --- a/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverMouseToOffsetActionTest.php @@ -17,8 +17,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverMouseToOffsetActionTest extends \PHPUnit_Framework_TestCase +class WebDriverMouseToOffsetActionTest extends TestCase { /** * @type WebDriverMoveToOffsetAction diff --git a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php index 9b06b3df7..22cb47e9d 100644 --- a/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php +++ b/tests/unit/Interactions/Internal/WebDriverSendKeysActionTest.php @@ -18,8 +18,9 @@ use Facebook\WebDriver\Internal\WebDriverLocatable; use Facebook\WebDriver\WebDriverKeyboard; use Facebook\WebDriver\WebDriverMouse; +use PHPUnit\Framework\TestCase; -class WebDriverSendKeysActionTest extends \PHPUnit_Framework_TestCase +class WebDriverSendKeysActionTest extends TestCase { /** @var WebDriverSendKeysAction */ private $webDriverSendKeysAction; diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index dacdcd139..559a21f7f 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -19,8 +19,9 @@ use Facebook\WebDriver\Firefox\FirefoxPreferences; use Facebook\WebDriver\Firefox\FirefoxProfile; use Facebook\WebDriver\WebDriverPlatform; +use PHPUnit\Framework\TestCase; -class DesiredCapabilitiesTest extends \PHPUnit_Framework_TestCase +class DesiredCapabilitiesTest extends TestCase { public function testShouldInstantiateWithCapabilitiesGivenInConstructor() { diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php index 63d004e6b..a3810e731 100644 --- a/tests/unit/Remote/HttpCommandExecutorTest.php +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -16,8 +16,9 @@ namespace Facebook\WebDriver\Remote; use phpmock\phpunit\PHPMock; +use PHPUnit\Framework\TestCase; -class HttpCommandExecutorTest extends \PHPUnit_Framework_TestCase +class HttpCommandExecutorTest extends TestCase { use PHPMock; diff --git a/tests/unit/Remote/RemoteWebDriverTest.php b/tests/unit/Remote/RemoteWebDriverTest.php index 48b149f84..c8fee7e5d 100644 --- a/tests/unit/Remote/RemoteWebDriverTest.php +++ b/tests/unit/Remote/RemoteWebDriverTest.php @@ -19,13 +19,14 @@ use Facebook\WebDriver\WebDriverNavigation; use Facebook\WebDriver\WebDriverOptions; use Facebook\WebDriver\WebDriverWait; +use PHPUnit\Framework\TestCase; /** * Unit part of RemoteWebDriver tests. Ie. tests for behavior which do not interact with the real remote server. * * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebDriver */ -class RemoteWebDriverTest extends \PHPUnit_Framework_TestCase +class RemoteWebDriverTest extends TestCase { /** @var RemoteWebDriver */ private $driver; diff --git a/tests/unit/Remote/RemoteWebElementTest.php b/tests/unit/Remote/RemoteWebElementTest.php index 45c057751..80bc92931 100644 --- a/tests/unit/Remote/RemoteWebElementTest.php +++ b/tests/unit/Remote/RemoteWebElementTest.php @@ -15,12 +15,14 @@ namespace Facebook\WebDriver\Remote; +use PHPUnit\Framework\TestCase; + /** * Unit part of RemoteWebDriver tests. Ie. tests for behavior which do not interact with the real remote server. * * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebElement */ -class RemoteWebElementTest extends \PHPUnit_Framework_TestCase +class RemoteWebElementTest extends TestCase { /** * @covers ::__construct diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php index 9993c6ce5..2e1a0ad9f 100644 --- a/tests/unit/Remote/WebDriverCommandTest.php +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -15,7 +15,9 @@ namespace Facebook\WebDriver\Remote; -class WebDriverCommandTest extends \PHPUnit_Framework_TestCase +use PHPUnit\Framework\TestCase; + +class WebDriverCommandTest extends TestCase { public function testShouldSetOptionsUsingConstructor() { diff --git a/tests/unit/Support/XPathEscaperTest.php b/tests/unit/Support/XPathEscaperTest.php index 21ac4aea0..96853ed4f 100644 --- a/tests/unit/Support/XPathEscaperTest.php +++ b/tests/unit/Support/XPathEscaperTest.php @@ -15,7 +15,9 @@ namespace Facebook\WebDriver\Support; -class XPathEscaperTest extends \PHPUnit_Framework_TestCase +use PHPUnit\Framework\TestCase; + +class XPathEscaperTest extends TestCase { /** * @dataProvider xpathProvider diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index e786167a8..1860e4585 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -20,11 +20,12 @@ use Facebook\WebDriver\Remote\RemoteExecuteMethod; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\RemoteWebElement; +use PHPUnit\Framework\TestCase; /** * @covers Facebook\WebDriver\WebDriverExpectedCondition */ -class WebDriverExpectedConditionTest extends \PHPUnit_Framework_TestCase +class WebDriverExpectedConditionTest extends TestCase { /** @var RemoteWebDriver|\PHPUnit_Framework_MockObject_MockObject */ private $driverMock; diff --git a/tests/unit/WebDriverKeysTest.php b/tests/unit/WebDriverKeysTest.php index 9a205c7de..a309402b8 100644 --- a/tests/unit/WebDriverKeysTest.php +++ b/tests/unit/WebDriverKeysTest.php @@ -15,10 +15,12 @@ namespace Facebook\WebDriver; +use PHPUnit\Framework\TestCase; + /** * @covers Facebook\WebDriver\WebDriverKeys */ -class WebDriverKeysTest extends \PHPUnit_Framework_TestCase +class WebDriverKeysTest extends TestCase { /** * @dataProvider provideKeys diff --git a/tests/unit/WebDriverOptionsTest.php b/tests/unit/WebDriverOptionsTest.php index 8bc47b96f..07c721c48 100644 --- a/tests/unit/WebDriverOptionsTest.php +++ b/tests/unit/WebDriverOptionsTest.php @@ -17,11 +17,12 @@ use Facebook\WebDriver\Remote\DriverCommand; use Facebook\WebDriver\Remote\ExecuteMethod; +use PHPUnit\Framework\TestCase; /** * @covers Facebook\WebDriver\WebDriverOptions */ -class WebDriverOptionsTest extends \PHPUnit_Framework_TestCase +class WebDriverOptionsTest extends TestCase { /** @var ExecuteMethod|\PHPUnit_Framework_MockObject_MockObject */ private $executor; From d3af34e78f8ca4edc7cff3dbcfbe8c0219d43c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 8 Nov 2017 13:45:10 +0100 Subject: [PATCH 187/600] Avoid useless test warning on PHPUnit 6 --- tests/unit/CookieTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 5fc62fb6c..43215acb8 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -145,7 +145,7 @@ public function testShouldBeCreatableFromAnArrayWithAllValues() * @param string $domain * @param string $expectedMessage */ - public function testShouldValidateCookie($name, $value, $domain, $expectedMessage) + public function testShouldValidateCookieOnConstruction($name, $value, $domain, $expectedMessage) { if ($expectedMessage) { $this->expectException(\InvalidArgumentException::class); @@ -156,6 +156,8 @@ public function testShouldValidateCookie($name, $value, $domain, $expectedMessag if ($domain !== null) { $cookie->setDomain($domain); } + + $this->assertInstanceOf(Cookie::class, $cookie); } /** From 1bb077b2fd7273569f63293bf623406d8a6c3cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=C3=A9nse?= Date: Tue, 6 Jun 2017 19:19:18 +0200 Subject: [PATCH 188/600] Fix typo in isJavascriptEnabled --- lib/Remote/DesiredCapabilities.php | 2 +- tests/unit/Remote/DesiredCapabilitiesTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 3990343af..940fcf98c 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -145,7 +145,7 @@ public function setJavascriptEnabled($enabled) $browser = $this->getBrowserName(); if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) { throw new Exception( - 'isJavascriptEnable() is a htmlunit-only option. ' . + 'isJavascriptEnabled() is a htmlunit-only option. ' . 'See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities.' ); } diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index dacdcd139..1edea2522 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -63,7 +63,7 @@ public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() /** * @expectedException \Exception - * @expectedExceptionMessage isJavascriptEnable() is a htmlunit-only option + * @expectedExceptionMessage isJavascriptEnabled() is a htmlunit-only option */ public function testShouldNotAllowToDisableJavascriptForNonHtmlUnitBrowser() { From b643bf3a465ca8eec35c781e8ac8c40d003e3151 Mon Sep 17 00:00:00 2001 From: VolCh Date: Sat, 4 Nov 2017 15:52:32 +0200 Subject: [PATCH 189/600] Extract DriverService::createProcess() --- lib/Remote/Service/DriverService.php | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index c15ef94f9..e3fea5823 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -81,12 +81,7 @@ public function start() return $this; } - $processBuilder = (new ProcessBuilder()) - ->setPrefix($this->executable) - ->setArguments($this->args) - ->addEnvironmentVariables($this->environment); - - $this->process = $processBuilder->getProcess(); + $this->process = $this->createProcess(); $this->process->start(); $checker = new URLChecker(); @@ -144,4 +139,17 @@ protected static function checkExecutable($executable) return $executable; } + + /** + * @return Process + */ + private function createProcess() + { + $processBuilder = (new ProcessBuilder()) + ->setPrefix($this->executable) + ->setArguments($this->args) + ->addEnvironmentVariables($this->environment); + + return $processBuilder->getProcess(); + } } From 3a2ecdf0e4a10b9e4c91e3aece999fbf6ccb1776 Mon Sep 17 00:00:00 2001 From: VolCh Date: Sat, 4 Nov 2017 16:13:40 +0200 Subject: [PATCH 190/600] Enable beta stability for project development only --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 94b7f8a36..8392c5738 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "forum": "https://www.facebook.com/groups/phpwebdriver/", "source": "https://github.com/facebook/php-webdriver" }, + "minimum-stability": "beta", "require": { "php": "^5.6 || ~7.0", "symfony/process": "^2.8 || ^3.1", From a19477c5a1177ef5da36884b7144232ba5a65d4d Mon Sep 17 00:00:00 2001 From: VolCh Date: Sat, 4 Nov 2017 16:16:11 +0200 Subject: [PATCH 191/600] Allow Symfony 4 and avoid deprecation warning with Symfony 3.4 --- composer.json | 4 ++-- lib/Remote/Service/DriverService.php | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 8392c5738..069cb6df5 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "minimum-stability": "beta", "require": { "php": "^5.6 || ~7.0", - "symfony/process": "^2.8 || ^3.1", + "symfony/process": "^2.8 || ^3.1 || ^4.0", "ext-curl": "*", "ext-zip": "*" }, @@ -25,7 +25,7 @@ "php-mock/php-mock-phpunit": "^1.1", "php-coveralls/php-coveralls": "^1.0.2", "guzzle/guzzle": "^3.4.1", - "symfony/var-dumper": "^3.3" + "symfony/var-dumper": "^3.3 || ^4.0" }, "autoload": { "psr-4": { diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php index e3fea5823..eabf24e7a 100644 --- a/lib/Remote/Service/DriverService.php +++ b/lib/Remote/Service/DriverService.php @@ -145,11 +145,20 @@ protected static function checkExecutable($executable) */ private function createProcess() { - $processBuilder = (new ProcessBuilder()) - ->setPrefix($this->executable) - ->setArguments($this->args) - ->addEnvironmentVariables($this->environment); + // BC: ProcessBuilder deprecated since Symfony 3.4 and removed in Symfony 4.0. + if (class_exists(ProcessBuilder::class) + && false === mb_strpos('@deprecated', (new \ReflectionClass(ProcessBuilder::class))->getDocComment()) + ) { + $processBuilder = (new ProcessBuilder()) + ->setPrefix($this->executable) + ->setArguments($this->args) + ->addEnvironmentVariables($this->environment); + + return $processBuilder->getProcess(); + } + // Safe to use since Symfony 3.3 + $commandLine = array_merge([$this->executable], $this->args); - return $processBuilder->getProcess(); + return new Process($commandLine, null, $this->environment); } } From 8d08a8d34ab20e3663ac2c1ff88e30edbc25a287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 15 Nov 2017 02:04:18 +0100 Subject: [PATCH 192/600] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b503b1d..0d71ee44d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,10 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased ### Changed - Drop PHP 5.5 support, the minimal required version of PHP is now PHP 5.6. +- Allow installation of Symfony 4 components. ### Added -- Added a visibilityOfAnyElementsLocated method to WebDriverExpectedCondition. +- Add a `visibilityOfAnyElementsLocated()` method to `WebDriverExpectedCondition`. ## 1.4.1 - 2017-04-28 ### Fixed From 86b5ca2f67173c9d34340845dd690149c886a605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 15 Nov 2017 12:08:09 +0100 Subject: [PATCH 193/600] Release version 1.5.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d71ee44d..3f42c31ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.5.0 - 2017-11-15 ### Changed - Drop PHP 5.5 support, the minimal required version of PHP is now PHP 5.6. - Allow installation of Symfony 4 components. From d9623ed86e1f4b88609ff0dd054b62682c2419e4 Mon Sep 17 00:00:00 2001 From: Flarnie Marchan Date: Sun, 26 Nov 2017 16:25:29 -0800 Subject: [PATCH 194/600] Link to COC from `CONTRIBUTING.md` We are about to add a `CODE_OF_CONDUCT.md` doc and it makes sense to surface it here. --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c59bbe84..d7b93736c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,9 @@ We love to have your help to make php-webdriver better! Feel free to open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem, or send a pull request (see bellow) with your contribution. +## Code of Conduct +The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) + ## Workflow when contributing a patch 1. Fork the project on GitHub From 90c7dcbff5a545d63520c83ab490d6e24ad9ba3a Mon Sep 17 00:00:00 2001 From: Flarnie Marchan Date: Sun, 26 Nov 2017 16:27:33 -0800 Subject: [PATCH 195/600] Add `CODE_OF_CONDUCT.md` In the past Facebook didn't promote including a Code of Conduct when creating new projects, and many projects skipped this important document. Let's fix it. :) **why make this change?:** Facebook Open Source provides a Code of Conduct statement for all projects to follow, to promote a welcoming and safe open source community. Exposing the COC via a separate markdown file is a standard being promoted by Github via the Community Profile in order to meet their Open Source Guide's recommended community standards. As you can see, adding this file will improve [the php-webdriver community profile](https://github.com/facebook/php-webdriver/community) checklist and increase the visibility of our COC. **test plan:** Viewing it on my branch - (Flarnie will insert screenshots) **issue:** internal task t23481323 --- CODE_OF_CONDUCT.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..0a45f9bd5 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated. From 52052a7e21075653de8a8b449097d16461ce5bc2 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Thu, 30 Nov 2017 19:13:05 -0200 Subject: [PATCH 196/600] Test against PHP 7.2 --- .travis.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7484f1cfc..81266034f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 env: global: @@ -16,29 +17,29 @@ env: matrix: include: # Add build to run tests against Firefox inside Travis environment - - php: 7.1 + - php: 7.2 env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" # Add build to run tests against Chrome inside Travis environment - - php: 7.1 + - php: 7.2 env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" addons: chrome: beta # Build with lowest possible dependencies - - php: 7.1 + - php: 7.2 env: DEPENDENCIES="--prefer-lowest" # Chrome on Travis build with lowest possible dependencies - - php: 7.1 + - php: 7.2 env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" DEPENDENCIES="--prefer-lowest" addons: chrome: beta # Saucelabs builds - - php: 7.1 + - php: 7.2 env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -47,7 +48,7 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: 7.1 + - php: 7.2 env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -56,7 +57,7 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: 7.1 + - php: 7.2 env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="15.15063" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -67,7 +68,7 @@ matrix: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= # Codestyle check build - - php: 7.1 + - php: 7.2 env: CHECK_CODESTYLE=1 before_script: ~ script: composer codestyle:check From d7cabc7fd357c1d8ccf43b5dbfb2116a74a193e0 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Wed, 6 Dec 2017 05:31:52 -0200 Subject: [PATCH 197/600] Use assertArrayNotHasKey --- tests/unit/CookieTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 43215acb8..ade9af68f 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -79,7 +79,7 @@ public function testShouldProvideArrayAccessToProperties(Cookie $cookie) $cookie->offsetSet('domain', 'bar.com'); $this->assertSame('bar.com', $cookie['domain']); $cookie->offsetUnset('domain'); - $this->assertFalse(isset($cookie['domain'])); + $this->assertArrayNotHasKey('domain', $cookie); } public function testShouldBeCreatableFromAnArrayWithBasicValues() @@ -94,23 +94,23 @@ public function testShouldBeCreatableFromAnArrayWithBasicValues() $this->assertSame('cookieName', $cookie['name']); $this->assertSame('someValue', $cookie['value']); - $this->assertFalse(isset($cookie['path'])); + $this->assertArrayNotHasKey('path', $cookie); $this->assertNull($cookie['path']); $this->assertNull($cookie->getPath()); - $this->assertFalse(isset($cookie['domain'])); + $this->assertArrayNotHasKey('domain', $cookie); $this->assertNull($cookie['domain']); $this->assertNull($cookie->getDomain()); - $this->assertFalse(isset($cookie['expiry'])); + $this->assertArrayNotHasKey('expiry', $cookie); $this->assertNull($cookie['expiry']); $this->assertNull($cookie->getExpiry()); - $this->assertFalse(isset($cookie['secure'])); + $this->assertArrayNotHasKey('secure', $cookie); $this->assertNull($cookie['secure']); $this->assertNull($cookie->isSecure()); - $this->assertFalse(isset($cookie['httpOnly'])); + $this->assertArrayNotHasKey('httpOnly', $cookie); $this->assertNull($cookie['httpOnly']); $this->assertNull($cookie->isHttpOnly()); } From 5f41a0bbec16fc719712089fc12399b0c1342f59 Mon Sep 17 00:00:00 2001 From: Dmitry Matora Date: Fri, 3 Nov 2017 20:29:01 +0300 Subject: [PATCH 198/600] Implemented timeout support. Solves #496 --- lib/Remote/RemoteWebDriver.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index f8b8e5e6e..3a8d3563f 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -139,11 +139,20 @@ public static function create( * * @param string $selenium_server_url The url of the remote Selenium WebDriver server * @param string $session_id The existing session id + * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server + * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server * @return RemoteWebDriver */ - public static function createBySessionID($session_id, $selenium_server_url = 'http://localhost:4444/wd/hub') + public static function createBySessionID($session_id, $selenium_server_url = 'http://localhost:4444/wd/hub', $connection_timeout_in_ms = null, $request_timeout_in_ms = null) { + $executor = new HttpCommandExecutor($selenium_server_url); + if ($connection_timeout_in_ms !== null) { + $executor->setConnectionTimeout($connection_timeout_in_ms); + } + if ($request_timeout_in_ms !== null) { + $executor->setRequestTimeout($request_timeout_in_ms); + } return new static($executor, $session_id); } From 21b62c4ceec300bbe63482c9027e3fc639aed3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 6 Dec 2017 18:35:19 +0100 Subject: [PATCH 199/600] Update chagnelog --- CHANGELOG.md | 2 ++ lib/Remote/RemoteWebDriver.php | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f42c31ef..a3adb0988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added +- Connection and request timeouts could be specified also when creating RemoteWebDriver from existing session ID. ## 1.5.0 - 2017-11-15 ### Changed diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 3a8d3563f..becab6b98 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -85,7 +85,7 @@ protected function __construct( * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server * @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through - * @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through + * @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through * @param DesiredCapabilities $required_capabilities The required capabilities * @return RemoteWebDriver */ @@ -143,9 +143,12 @@ public static function create( * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server * @return RemoteWebDriver */ - public static function createBySessionID($session_id, $selenium_server_url = 'http://localhost:4444/wd/hub', $connection_timeout_in_ms = null, $request_timeout_in_ms = null) - { - + public static function createBySessionID( + $session_id, + $selenium_server_url = 'http://localhost:4444/wd/hub', + $connection_timeout_in_ms = null, + $request_timeout_in_ms = null + ) { $executor = new HttpCommandExecutor($selenium_server_url); if ($connection_timeout_in_ms !== null) { $executor->setConnectionTimeout($connection_timeout_in_ms); From 32d5b8d8ba1161bff5838ebc70689560f6964211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 7 Dec 2017 00:35:05 +0100 Subject: [PATCH 200/600] Fix ChromeDriver declaration to match the parent class --- lib/Chrome/ChromeDriver.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 8ba76583c..832ca17a8 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -82,13 +82,16 @@ public static function create( * * @param string $session_id The existing session id * @param string $selenium_server_url The url of the remote Selenium WebDriver server - * + * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server + * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server * @throws WebDriverException * @return RemoteWebDriver|void */ public static function createBySessionID( $session_id, - $selenium_server_url = 'http://localhost:4444/wd/hub' + $selenium_server_url = 'http://localhost:4444/wd/hub', + $connection_timeout_in_ms = null, + $request_timeout_in_ms = null ) { throw new WebDriverException('Please use ChromeDriver::start() instead.'); } From 6baf65f9c62378a775900da2c6168888649b6f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Dec 2017 12:19:10 +0100 Subject: [PATCH 201/600] Upgrade php-coveralls to v 2.0.0 --- .travis.yml | 2 +- composer.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7484f1cfc..18db2fc36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -106,4 +106,4 @@ after_script: - if [ -f ./logs/php-server.log ]; then cat ./logs/php-server.log; fi after_success: - - travis_retry php vendor/bin/coveralls -v + - travis_retry php vendor/bin/php-coveralls -v diff --git a/composer.json b/composer.json index 069cb6df5..6aa6ef61b 100644 --- a/composer.json +++ b/composer.json @@ -23,8 +23,7 @@ "friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", - "php-coveralls/php-coveralls": "^1.0.2", - "guzzle/guzzle": "^3.4.1", + "php-coveralls/php-coveralls": "^2.0", "symfony/var-dumper": "^3.3 || ^4.0" }, "autoload": { From cec193f66be978d107ad50112d1ad4546b255e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 9 Dec 2017 01:04:31 +0100 Subject: [PATCH 202/600] Use PHPStan for static analysis --- .travis.yml | 5 ++++- composer.json | 3 +++ lib/Firefox/FirefoxProfile.php | 2 +- lib/Support/Events/EventFiringWebDriver.php | 6 +++--- lib/Support/Events/EventFiringWebDriverNavigation.php | 2 +- lib/Support/Events/EventFiringWebElement.php | 2 +- lib/WebDriverExpectedCondition.php | 4 ++-- lib/WebDriverHasInputDevices.php | 2 +- phpstan.neon | 10 ++++++++++ tests/functional/WebDriverByTest.php | 4 ++-- 10 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 phpstan.neon diff --git a/.travis.yml b/.travis.yml index 18db2fc36..07687e845 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,10 @@ matrix: - php: 7.1 env: CHECK_CODESTYLE=1 before_script: ~ - script: composer codestyle:check + script: + - composer require phpstan/phpstan-shim # Not part of require-dev, because it won't install on PHP 5.6 + - composer analyze + - composer codestyle:check after_script: ~ after_success: ~ diff --git a/composer.json b/composer.json index 6aa6ef61b..c865ad691 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,9 @@ "codestyle:fix": [ "vendor/bin/php-cs-fixer fix --diff || exit 0", "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" + ], + "analyze": [ + "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi" ] }, "extra": { diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 8086198ca..b9d36b30e 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -110,7 +110,7 @@ public function setPreference($key, $value) } /** - * @param $key + * @param mixed $key * @return mixed */ public function getPreference($key) diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php index c129ef015..5a75dbe1f 100644 --- a/lib/Support/Events/EventFiringWebDriver.php +++ b/lib/Support/Events/EventFiringWebDriver.php @@ -133,7 +133,7 @@ public function findElement(WebDriverBy $by) } /** - * @param $script + * @param string $script * @param array $arguments * @throws WebDriverException * @return mixed @@ -161,7 +161,7 @@ public function executeScript($script, array $arguments = []) } /** - * @param $script + * @param string $script * @param array $arguments * @throws WebDriverException * @return mixed @@ -396,7 +396,7 @@ protected function newElement(WebDriverElement $element) /** * @param mixed $method - * @param mixed $arguments,... + * @param mixed ...$arguments */ protected function dispatch($method, ...$arguments) { diff --git a/lib/Support/Events/EventFiringWebDriverNavigation.php b/lib/Support/Events/EventFiringWebDriverNavigation.php index 0008ebbdc..7d8920eb1 100644 --- a/lib/Support/Events/EventFiringWebDriverNavigation.php +++ b/lib/Support/Events/EventFiringWebDriverNavigation.php @@ -149,7 +149,7 @@ public function to($url) /** * @param mixed $method - * @param mixed $arguments,... + * @param mixed ...$arguments */ protected function dispatch($method, ...$arguments) { diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index 099bb3573..9595953cf 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -392,7 +392,7 @@ protected function dispatchOnException(WebDriverException $exception) /** * @param mixed $method - * @param mixed $arguments,... + * @param mixed ...$arguments */ protected function dispatch($method, ...$arguments) { diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 433ee1a3a..d9ceb5dde 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -213,7 +213,7 @@ function (WebDriver $driver) use ($by) { if ($element->isDisplayed()) { $visibleElements[] = $element; } - } catch (StateElementReferenceException $e) { + } catch (StaleElementReferenceException $e) { } } @@ -399,7 +399,7 @@ function (WebDriver $driver) use ($by) { /** * An expectation for checking that an element with text is either invisible or not present on the DOM. * - * @param WebdriverBy $by The locator used to find the element. + * @param WebDriverBy $by The locator used to find the element. * @param string $text The text of the element. * @return WebDriverExpectedCondition Condition returns whether the text is found in the element located. */ diff --git a/lib/WebDriverHasInputDevices.php b/lib/WebDriverHasInputDevices.php index 93e42a30a..7cb1992eb 100644 --- a/lib/WebDriverHasInputDevices.php +++ b/lib/WebDriverHasInputDevices.php @@ -21,7 +21,7 @@ interface WebDriverHasInputDevices { /** - * @return WebDriverKeyBoard + * @return WebDriverKeyboard */ public function getKeyboard(); diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 000000000..7023c466e --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,10 @@ +parameters: + ignoreErrors: + - '#Class Symfony\\Component\\Process\\ProcessBuilder not found.#' + - '#Instantiated class Symfony\\Component\\Process\\ProcessBuilder not found.#' + - '#Call to method setPrefix\(\) on an unknown class Symfony\\Component\\Process\\ProcessBuilder#' + # To be fixed: + - '#Call to an undefined method RecursiveIteratorIterator::getSubPathName\(\)#' + - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#' + - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::getCoordinates\(\)#' + - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::equals\(\)#' diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php index 43d8c0457..534b145f0 100644 --- a/tests/functional/WebDriverByTest.php +++ b/tests/functional/WebDriverByTest.php @@ -25,8 +25,8 @@ class WebDriverByTest extends WebDriverTestCase { /** * @dataProvider textElementsProvider - * @param $webDriverByLocatorMethod - * @param $webDriverByLocatorValue + * @param string $webDriverByLocatorMethod + * @param string $webDriverByLocatorValue * @param string $expectedText * @param string $expectedAttributeValue */ From cc69cf0bbd807be3b8111098e03c46621d47e695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 9 Dec 2017 01:06:04 +0100 Subject: [PATCH 203/600] Use createMock shortcut contained in new PHPUnit --- tests/unit/WebDriverExpectedConditionTest.php | 45 ++++++------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index c4d734015..abcd5537b 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -34,11 +34,7 @@ class WebDriverExpectedConditionTest extends TestCase protected function setUp() { - // TODO: replace with createMock() once PHP 5.5 support is dropped - $this->driverMock = $this - ->getMockBuilder(RemoteWebDriver::class) - ->disableOriginalConstructor() - ->getMock(); + $this->driverMock = $this->createMock(RemoteWebDriver::class); $this->wait = new WebDriverWait($this->driverMock, 1, 1); } @@ -141,7 +137,7 @@ public function testShouldDetectPresenceOfElementLocatedCondition() public function testShouldDetectPresenceOfAllElementsLocatedByCondition() { - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $this->driverMock->expects($this->at(0)) ->method('findElements') @@ -166,7 +162,7 @@ public function testShouldDetectVisibilityOfElementLocatedCondition() // Call #3: return Element, but isDisplayed will return false // Call #4: return Element, isDisplayed will true and condition will match - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) ->method('isDisplayed') ->willThrowException(new StaleElementReferenceException('')); @@ -189,9 +185,9 @@ public function testShouldDetectVisibilityOfElementLocatedCondition() public function testShouldDetectVisibilityOfAnyElementLocated() { $elementList = [ - $this->createRemoteWebElementMock(), - $this->createRemoteWebElementMock(), - $this->createRemoteWebElementMock(), + $this->createMock(RemoteWebElement::class), + $this->createMock(RemoteWebElement::class), + $this->createMock(RemoteWebElement::class), ]; $elementList[0]->expects($this->once()) @@ -218,7 +214,7 @@ public function testShouldDetectVisibilityOfAnyElementLocated() public function testShouldDetectInvisibilityOfElementLocatedConditionOnNoSuchElementException() { - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $this->driverMock->expects($this->at(0)) ->method('findElement') @@ -241,7 +237,7 @@ public function testShouldDetectInvisibilityOfElementLocatedConditionOnNoSuchEle public function testShouldDetectInvisibilityOfElementLocatedConditionOnStaleElementReferenceException() { - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $this->driverMock->expects($this->exactly(2)) ->method('findElement') @@ -263,7 +259,7 @@ public function testShouldDetectInvisibilityOfElementLocatedConditionOnStaleElem public function testShouldDetectInvisibilityOfElementLocatedConditionWhenElementBecamesInvisible() { - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $this->driverMock->expects($this->exactly(2)) ->method('findElement') @@ -285,7 +281,7 @@ public function testShouldDetectInvisibilityOfElementLocatedConditionWhenElement public function testShouldDetectVisibilityOfCondition() { - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) ->method('isDisplayed') ->willReturn(false); @@ -307,7 +303,7 @@ public function testShouldDetectElementTextContainsCondition() // Call #3: return Element, but getText will throw StaleElementReferenceException // Call #4: return Element, getText will return new text and condition will match - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) ->method('getText') ->willReturn('this is an old text'); @@ -335,7 +331,7 @@ public function testShouldDetectElementTextIsCondition() // Call #3: return Element, getText will return not-matching text // Call #4: return Element, getText will return new text and condition will match - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) ->method('getText') ->willThrowException(new StaleElementReferenceException('')); @@ -366,7 +362,7 @@ public function testShouldDetectElementTextMatchesCondition() // Call #3: return Element, getText will return not-matching text // Call #4: return Element, getText will return matching text - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) ->method('getText') @@ -398,7 +394,7 @@ public function testShouldDetectElementValueContainsCondition() // Call #3: return Element, getAttribute('value') will return not-matching text // Call #4: return Element, getAttribute('value') will return matching text - $element = $this->createRemoteWebElementMock(); + $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) ->method('getAttribute') @@ -456,17 +452,4 @@ private function setupDriverToReturnElementAfterAnException($element, $expectedN ->willReturn($element); } } - - /** - * @todo Replace with createMock() once PHP 5.5 support is dropped - * @return \PHPUnit_Framework_MockObject_MockObject|RemoteWebElement - */ - private function createRemoteWebElementMock() - { - return $this->getMockBuilder(RemoteWebElement::class) - ->disableOriginalConstructor() - ->disableOriginalClone() - ->disableArgumentCloning() - ->getMock(); - } } From 4962d348f5e71c284bebc59ab7dd54607518ee4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 9 Dec 2017 01:07:34 +0100 Subject: [PATCH 204/600] Use absolute FQCN in annotation --- tests/functional/Chrome/ChromeDriverServiceTest.php | 4 ++-- tests/functional/Chrome/ChromeDriverTest.php | 2 +- tests/functional/FileUploadTest.php | 4 ++-- tests/functional/RemoteWebDriverCreateTest.php | 4 ++-- tests/functional/RemoteWebDriverFindElementTest.php | 2 +- tests/functional/RemoteWebDriverTest.php | 4 ++-- tests/functional/RemoteWebElementTest.php | 2 +- tests/functional/WebDriverActionsTest.php | 2 +- tests/functional/WebDriverAlertTest.php | 2 +- tests/functional/WebDriverByTest.php | 2 +- tests/functional/WebDriverNavigationTest.php | 2 +- tests/functional/WebDriverSelectTest.php | 4 ++-- tests/functional/WebDriverTimeoutsTest.php | 2 +- tests/unit/CookieTest.php | 2 +- tests/unit/Remote/RemoteWebDriverTest.php | 2 +- tests/unit/Remote/RemoteWebElementTest.php | 2 +- tests/unit/WebDriverExpectedConditionTest.php | 2 +- tests/unit/WebDriverKeysTest.php | 2 +- tests/unit/WebDriverOptionsTest.php | 2 +- 19 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/functional/Chrome/ChromeDriverServiceTest.php b/tests/functional/Chrome/ChromeDriverServiceTest.php index bc1a1b92f..781a68bae 100644 --- a/tests/functional/Chrome/ChromeDriverServiceTest.php +++ b/tests/functional/Chrome/ChromeDriverServiceTest.php @@ -19,8 +19,8 @@ /** * @group exclude-saucelabs - * @covers Facebook\WebDriver\Chrome\ChromeDriverService - * @covers Facebook\WebDriver\Remote\Service\DriverService + * @covers \Facebook\WebDriver\Chrome\ChromeDriverService + * @covers \Facebook\WebDriver\Remote\Service\DriverService */ class ChromeDriverServiceTest extends TestCase { diff --git a/tests/functional/Chrome/ChromeDriverTest.php b/tests/functional/Chrome/ChromeDriverTest.php index 476033839..b8066156e 100644 --- a/tests/functional/Chrome/ChromeDriverTest.php +++ b/tests/functional/Chrome/ChromeDriverTest.php @@ -21,7 +21,7 @@ /** * @group exclude-saucelabs - * @covers Facebook\WebDriver\Chrome\ChromeDriver + * @covers \Facebook\WebDriver\Chrome\ChromeDriver */ class ChromeDriverTest extends TestCase { diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index e88139953..5b2f6d2d3 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -18,8 +18,8 @@ use Facebook\WebDriver\Remote\LocalFileDetector; /** - * @covers Facebook\WebDriver\Remote\LocalFileDetector - * @covers Facebook\WebDriver\Remote\RemoteWebElement + * @covers \Facebook\WebDriver\Remote\LocalFileDetector + * @covers \Facebook\WebDriver\Remote\RemoteWebElement */ class FileUploadTest extends WebDriverTestCase { diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 3140b26b0..f9d7e809e 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -20,8 +20,8 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; /** - * @covers Facebook\WebDriver\Remote\RemoteWebDriver - * @covers Facebook\WebDriver\Remote\HttpCommandExecutor + * @covers \Facebook\WebDriver\Remote\RemoteWebDriver + * @covers \Facebook\WebDriver\Remote\HttpCommandExecutor */ class RemoteWebDriverCreateTest extends WebDriverTestCase { diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 46affc025..eea14b6e5 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -20,7 +20,7 @@ /** * Tests for findElement() and findElements() method of RemoteWebDriver. - * @covers Facebook\WebDriver\Remote\RemoteWebDriver + * @covers \Facebook\WebDriver\Remote\RemoteWebDriver */ class RemoteWebDriverFindElementTest extends WebDriverTestCase { diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 006b17c7b..440776ad5 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -20,7 +20,7 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebDriver + * @coversDefaultClass \Facebook\WebDriver\Remote\RemoteWebDriver */ class RemoteWebDriverTest extends WebDriverTestCase { @@ -170,7 +170,7 @@ function(){document.getElementById("id_test").innerHTML = "Text changed by scrip /** * @covers ::executeAsyncScript - * @covers Facebook\WebDriver\WebDriverTimeouts::setScriptTimeout + * @covers \Facebook\WebDriver\WebDriverTimeouts::setScriptTimeout */ public function testShouldExecuteAsyncScriptAndWaitUntilItIsFinished() { diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 51f414a93..d4614a431 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -19,7 +19,7 @@ use Facebook\WebDriver\Remote\RemoteWebElement; /** - * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebElement + * @coversDefaultClass \Facebook\WebDriver\Remote\RemoteWebElement */ class RemoteWebElementTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 173f7794c..188c76cd9 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -18,7 +18,7 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @coversDefaultClass Facebook\WebDriver\Interactions\WebDriverActions + * @coversDefaultClass \Facebook\WebDriver\Interactions\WebDriverActions */ class WebDriverActionsTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index 08d8ef73c..163bee157 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -19,7 +19,7 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @covers Facebook\WebDriver\WebDriverAlert + * @covers \Facebook\WebDriver\WebDriverAlert */ class WebDriverAlertTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php index 534b145f0..028db7920 100644 --- a/tests/functional/WebDriverByTest.php +++ b/tests/functional/WebDriverByTest.php @@ -19,7 +19,7 @@ /** * Tests for locator strategies provided by WebDriverBy. - * @covers Facebook\WebDriver\WebDriverBy + * @covers \Facebook\WebDriver\WebDriverBy */ class WebDriverByTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverNavigationTest.php b/tests/functional/WebDriverNavigationTest.php index 4f7dba252..d3aaebcb6 100644 --- a/tests/functional/WebDriverNavigationTest.php +++ b/tests/functional/WebDriverNavigationTest.php @@ -16,7 +16,7 @@ namespace Facebook\WebDriver; /** - * @coversDefaultClass Facebook\WebDriver\WebDriverNavigation + * @coversDefaultClass \Facebook\WebDriver\WebDriverNavigation */ class WebDriverNavigationTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverSelectTest.php b/tests/functional/WebDriverSelectTest.php index 9cd6cf250..37ad416af 100644 --- a/tests/functional/WebDriverSelectTest.php +++ b/tests/functional/WebDriverSelectTest.php @@ -20,8 +20,8 @@ use Facebook\WebDriver\Exception\UnsupportedOperationException; /** - * @covers Facebook\WebDriver\WebDriverSelect - * @covers Facebook\WebDriver\Exception\UnexpectedTagNameException + * @covers \Facebook\WebDriver\WebDriverSelect + * @covers \Facebook\WebDriver\Exception\UnexpectedTagNameException */ class WebDriverSelectTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index 808a494ab..69d143cc4 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -22,7 +22,7 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @coversDefaultClass Facebook\WebDriver\WebDriverTimeouts + * @coversDefaultClass \Facebook\WebDriver\WebDriverTimeouts */ class WebDriverTimeoutsTest extends WebDriverTestCase { diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index ade9af68f..3a0679d2c 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -18,7 +18,7 @@ use PHPUnit\Framework\TestCase; /** - * @covers Facebook\WebDriver\Cookie + * @covers \Facebook\WebDriver\Cookie */ class CookieTest extends TestCase { diff --git a/tests/unit/Remote/RemoteWebDriverTest.php b/tests/unit/Remote/RemoteWebDriverTest.php index c8fee7e5d..c5e397e00 100644 --- a/tests/unit/Remote/RemoteWebDriverTest.php +++ b/tests/unit/Remote/RemoteWebDriverTest.php @@ -24,7 +24,7 @@ /** * Unit part of RemoteWebDriver tests. Ie. tests for behavior which do not interact with the real remote server. * - * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebDriver + * @coversDefaultClass \Facebook\WebDriver\Remote\RemoteWebDriver */ class RemoteWebDriverTest extends TestCase { diff --git a/tests/unit/Remote/RemoteWebElementTest.php b/tests/unit/Remote/RemoteWebElementTest.php index 80bc92931..e1b0a2b47 100644 --- a/tests/unit/Remote/RemoteWebElementTest.php +++ b/tests/unit/Remote/RemoteWebElementTest.php @@ -20,7 +20,7 @@ /** * Unit part of RemoteWebDriver tests. Ie. tests for behavior which do not interact with the real remote server. * - * @coversDefaultClass Facebook\WebDriver\Remote\RemoteWebElement + * @coversDefaultClass \Facebook\WebDriver\Remote\RemoteWebElement */ class RemoteWebElementTest extends TestCase { diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index abcd5537b..8cd4203a9 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -23,7 +23,7 @@ use PHPUnit\Framework\TestCase; /** - * @covers Facebook\WebDriver\WebDriverExpectedCondition + * @covers \Facebook\WebDriver\WebDriverExpectedCondition */ class WebDriverExpectedConditionTest extends TestCase { diff --git a/tests/unit/WebDriverKeysTest.php b/tests/unit/WebDriverKeysTest.php index a309402b8..71fef3b9e 100644 --- a/tests/unit/WebDriverKeysTest.php +++ b/tests/unit/WebDriverKeysTest.php @@ -18,7 +18,7 @@ use PHPUnit\Framework\TestCase; /** - * @covers Facebook\WebDriver\WebDriverKeys + * @covers \Facebook\WebDriver\WebDriverKeys */ class WebDriverKeysTest extends TestCase { diff --git a/tests/unit/WebDriverOptionsTest.php b/tests/unit/WebDriverOptionsTest.php index 07c721c48..dd7494c67 100644 --- a/tests/unit/WebDriverOptionsTest.php +++ b/tests/unit/WebDriverOptionsTest.php @@ -20,7 +20,7 @@ use PHPUnit\Framework\TestCase; /** - * @covers Facebook\WebDriver\WebDriverOptions + * @covers \Facebook\WebDriver\WebDriverOptions */ class WebDriverOptionsTest extends TestCase { From bc2b2d520ac8dfb6576b2c86d00999538c4c57d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 9 Dec 2017 01:19:25 +0100 Subject: [PATCH 205/600] Lint PHP files --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c865ad691..aaff428b5 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", "php-coveralls/php-coveralls": "^2.0", - "symfony/var-dumper": "^3.3 || ^4.0" + "symfony/var-dumper": "^3.3 || ^4.0", + "jakub-onderka/php-parallel-lint": "^0.9.2" }, "autoload": { "psr-4": { @@ -47,6 +48,7 @@ "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" ], "analyze": [ + "vendor/bin/parallel-lint -j 10 ./lib ./tests", "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi" ] }, From 0750ede674372496e7564882e7d673265b35f055 Mon Sep 17 00:00:00 2001 From: Alexandr Motuzov Date: Fri, 29 Dec 2017 23:03:50 +0500 Subject: [PATCH 206/600] Add `ext-mbstring` to requirements `mb_strpos` function is used in several places in the project. Many features will not work without `ext-mbstring` installed. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index aaff428b5..a96b82fe5 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "php": "^5.6 || ~7.0", "symfony/process": "^2.8 || ^3.1 || ^4.0", "ext-curl": "*", - "ext-zip": "*" + "ext-zip": "*", + "ext-mbstring": "*" }, "require-dev": { "phpunit/phpunit": "^5.7", From 7c69d51ed8b2ce845b4b39fe01b822628f429587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 2 Jan 2018 12:32:43 +0100 Subject: [PATCH 207/600] Remove xdebug to spped up codestyle check build --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 07687e845..1c6c75cd9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,6 +69,8 @@ matrix: # Codestyle check build - php: 7.1 env: CHECK_CODESTYLE=1 + before_install: + - phpenv config-rm xdebug.ini before_script: ~ script: - composer require phpstan/phpstan-shim # Not part of require-dev, because it won't install on PHP 5.6 @@ -82,10 +84,8 @@ cache: - $HOME/.composer/cache - jar -before_install: - - travis_retry composer self-update - install: + - travis_retry composer self-update - travis_retry composer update --no-interaction $DEPENDENCIES before_script: From fda6f7f6d45ed5baa2f6ce2cd9ba3d57e165b42d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 14 Jan 2018 00:21:39 +0100 Subject: [PATCH 208/600] Use a workaround for Chrome crashing on startup on Travis https://github.com/SeleniumHQ/selenium/issues/4961 --- tests/functional/Chrome/ChromeDriverTest.php | 9 ++++++++- tests/functional/WebDriverTestCase.php | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/functional/Chrome/ChromeDriverTest.php b/tests/functional/Chrome/ChromeDriverTest.php index b8066156e..89eb766cd 100644 --- a/tests/functional/Chrome/ChromeDriverTest.php +++ b/tests/functional/Chrome/ChromeDriverTest.php @@ -15,6 +15,7 @@ namespace Facebook\WebDriver\Chrome; +use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\Service\DriverCommandExecutor; use PHPUnit\Framework\TestCase; @@ -47,7 +48,13 @@ public function testShouldStartChromeDriver() // The createDefaultService() method expect path to the executable to be present in the environment variable putenv(ChromeDriverService::CHROME_DRIVER_EXE_PROPERTY . '=' . getenv('CHROMEDRIVER_PATH')); - $this->driver = ChromeDriver::start(); + // Add --no-sandbox as a workaround for Chrome crashing: https://github.com/SeleniumHQ/selenium/issues/4961 + $chromeOptions = new ChromeOptions(); + $chromeOptions->addArguments(['--no-sandbox']); + $desiredCapabilities = DesiredCapabilities::chrome(); + $desiredCapabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); + + $this->driver = ChromeDriver::start($desiredCapabilities); $this->assertInstanceOf(ChromeDriver::class, $this->driver); $this->assertInstanceOf(DriverCommandExecutor::class, $this->driver->getCommandExecutor()); diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 4abaf7c03..e9714a87c 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -55,7 +55,8 @@ protected function setUp() if ($browserName === WebDriverBrowserType::CHROME) { $chromeOptions = new ChromeOptions(); - $chromeOptions->addArguments(['--headless', 'window-size=1024,768']); + // --no-sandbox is a workaround for Chrome crashing: https://github.com/SeleniumHQ/selenium/issues/4961 + $chromeOptions->addArguments(['--headless', 'window-size=1024,768', '--no-sandbox']); $this->desiredCapabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); } From 21412fe9ce48ec8c23508879b73d78aa36c038ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 14 Jan 2018 00:25:19 +0100 Subject: [PATCH 209/600] Update Chromedriver and use stable chrome in Travis builds --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1c6c75cd9..3ee125011 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ env: global: - DISPLAY=:99.0 - BROWSER_NAME="htmlunit" - - CHROMEDRIVER_VERSION="2.31" + - CHROMEDRIVER_VERSION="2.35" matrix: include: @@ -25,7 +25,7 @@ matrix: - php: 7.1 env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" addons: - chrome: beta + chrome: stable # Build with lowest possible dependencies - php: 7.1 @@ -35,7 +35,7 @@ matrix: - php: 7.1 env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" DEPENDENCIES="--prefer-lowest" addons: - chrome: beta + chrome: stable # Saucelabs builds - php: 7.1 From 04b741060ea0f4fc0a4e3822a10b461005362a52 Mon Sep 17 00:00:00 2001 From: Stephanyan Date: Thu, 8 Feb 2018 22:53:17 +0100 Subject: [PATCH 210/600] Add .vscode folder to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 42ef8b562..deb25f3ae 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ logs/ *~ *.swp .idea +.vscode From 5c724f1b73e20a8241179df36db1b636170cd405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 16 Feb 2018 00:33:29 +0000 Subject: [PATCH 211/600] Remove invalid phpDoc return tags --- lib/WebDriverExpectedCondition.php | 58 ++++++++++++++---------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index d9ceb5dde..505474dfd 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -51,7 +51,7 @@ public function getApply() * An expectation for checking the title of a page. * * @param string $title The expected title, which must be an exact match. - * @return WebDriverExpectedCondition Condition returns whether current page title equals given string. + * @return static Condition returns whether current page title equals given string. */ public static function titleIs($title) { @@ -66,7 +66,7 @@ function (WebDriver $driver) use ($title) { * An expectation for checking substring of a page Title. * * @param string $title The expected substring of Title. - * @return WebDriverExpectedCondition Condition returns whether current page title contains given string. + * @return static Condition returns whether current page title contains given string. */ public static function titleContains($title) { @@ -81,8 +81,7 @@ function (WebDriver $driver) use ($title) { * An expectation for checking current page title matches the given regular expression. * * @param string $titleRegexp The regular expression to test against. - * @return WebDriverExpectedCondition Condition returns whether current page title matches the regular - * expression. + * @return static Condition returns whether current page title matches the regular expression. */ public static function titleMatches($titleRegexp) { @@ -97,7 +96,7 @@ function (WebDriver $driver) use ($titleRegexp) { * An expectation for checking the URL of a page. * * @param string $url The expected URL, which must be an exact match. - * @return WebDriverExpectedCondition Condition returns whether current URL equals given one. + * @return static Condition returns whether current URL equals given one. */ public static function urlIs($url) { @@ -112,7 +111,7 @@ function (WebDriver $driver) use ($url) { * An expectation for checking substring of the URL of a page. * * @param string $url The expected substring of the URL - * @return WebDriverExpectedCondition Condition returns whether current URL contains given string. + * @return static Condition returns whether current URL contains given string. */ public static function urlContains($url) { @@ -127,7 +126,7 @@ function (WebDriver $driver) use ($url) { * An expectation for checking current page URL matches the given regular expression. * * @param string $urlRegexp The regular expression to test against. - * @return WebDriverExpectedCondition Condition returns whether current URL matches the regular expression. + * @return static Condition returns whether current URL matches the regular expression. */ public static function urlMatches($urlRegexp) { @@ -143,7 +142,7 @@ function (WebDriver $driver) use ($urlRegexp) { * This does not necessarily mean that the element is visible. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition Condition returns the element which is located. + * @return static Condition returns the WebDriverElement which is located. */ public static function presenceOfElementLocated(WebDriverBy $by) { @@ -158,7 +157,7 @@ function (WebDriver $driver) use ($by) { * An expectation for checking that there is at least one element present on a web page. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition Condition returns an array of WebDriverElements once they are located. + * @return static Condition return an array of WebDriverElement once they are located. */ public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) { @@ -176,7 +175,7 @@ function (WebDriver $driver) use ($by) { * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition Condition returns the element which is located and visible. + * @return static Condition returns the WebDriverElement which is located and visible. */ public static function visibilityOfElementLocated(WebDriverBy $by) { @@ -199,7 +198,7 @@ function (WebDriver $driver) use ($by) { * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverBy $by The located used to find the element. - * @return WebDriverExpectedCondition Condition returns the elements that are located and visible. + * @return static Condition returns the array of WebDriverElement that are located and visible. */ public static function visibilityOfAnyElementLocated(WebDriverBy $by) { @@ -227,8 +226,7 @@ function (WebDriver $driver) use ($by) { * Visibility means that the element is not only displayed but also has a height and width that is greater than 0. * * @param WebDriverElement $element The element to be checked. - * @return WebDriverExpectedCondition Condition returns the same WebDriverElement once it is - * visible. + * @return static Condition returns the same WebDriverElement once it is visible. */ public static function visibilityOf(WebDriverElement $element) { @@ -247,7 +245,7 @@ function () use ($element) { * @deprecated Use WebDriverExpectedCondition::elementTextContains() instead * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. - * @return WebDriverExpectedCondition Condition returns whether the text is present in the element. + * @return static Condition returns whether the text is present in the element. */ public static function textToBePresentInElement(WebDriverBy $by, $text) { @@ -260,7 +258,7 @@ public static function textToBePresentInElement(WebDriverBy $by, $text) * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element. - * @return WebDriverExpectedCondition Condition returns whether the partial text is present in the element. + * @return static Condition returns whether the partial text is present in the element. */ public static function elementTextContains(WebDriverBy $by, $text) { @@ -283,7 +281,7 @@ function (WebDriver $driver) use ($by, $text) { * * @param WebDriverBy $by The locator used to find the element. * @param string $text The expected text of the element. - * @return WebDriverExpectedCondition Condition returns whether the element has text value equal to given one. + * @return static Condition returns whether the element has text value equal to given one. */ public static function elementTextIs(WebDriverBy $by, $text) { @@ -303,7 +301,7 @@ function (WebDriver $driver) use ($by, $text) { * * @param WebDriverBy $by The locator used to find the element. * @param string $regexp The regular expression to test against. - * @return WebDriverExpectedCondition Condition returns whether the element has text value equal to given one. + * @return static Condition returns whether the element has text value equal to given one. */ public static function elementTextMatches(WebDriverBy $by, $regexp) { @@ -325,7 +323,7 @@ function (WebDriver $driver) use ($by, $regexp) { * @deprecated Use WebDriverExpectedCondition::elementValueContains() instead * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element value. - * @return WebDriverExpectedCondition Condition returns whether the text is present in value attribute. + * @return static Condition returns whether the text is present in value attribute. */ public static function textToBePresentInElementValue(WebDriverBy $by, $text) { @@ -337,7 +335,7 @@ public static function textToBePresentInElementValue(WebDriverBy $by, $text) * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text to be presented in the element value. - * @return WebDriverExpectedCondition Condition returns whether the text is present in value attribute. + * @return static Condition returns whether the text is present in value attribute. */ public static function elementValueContains(WebDriverBy $by, $text) { @@ -359,8 +357,7 @@ function (WebDriver $driver) use ($by, $text) { * * @param string $frame_locator The locator used to find the iFrame * expected to be either the id or name value of the i/frame - * @return WebDriverExpectedCondition Condition returns object focused on new frame when frame is - * found, false otherwise. + * @return static Condition returns object focused on new frame when frame is found, false otherwise. */ public static function frameToBeAvailableAndSwitchToIt($frame_locator) { @@ -379,7 +376,7 @@ function (WebDriver $driver) use ($frame_locator) { * An expectation for checking that an element is either invisible or not present on the DOM. * * @param WebDriverBy $by The locator used to find the element. - * @return WebDriverExpectedCondition Condition returns whether no visible element located. + * @return static Condition returns whether no visible element located. */ public static function invisibilityOfElementLocated(WebDriverBy $by) { @@ -401,7 +398,7 @@ function (WebDriver $driver) use ($by) { * * @param WebDriverBy $by The locator used to find the element. * @param string $text The text of the element. - * @return WebDriverExpectedCondition Condition returns whether the text is found in the element located. + * @return static Condition returns whether the text is found in the element located. */ public static function invisibilityOfElementWithText(WebDriverBy $by, $text) { @@ -422,8 +419,7 @@ function (WebDriver $driver) use ($by, $text) { * An expectation for checking an element is visible and enabled such that you can click it. * * @param WebDriverBy $by The locator used to find the element - * @return WebDriverExpectedCondition Condition return the WebDriverElement once it is located, - * visible and clickable. + * @return static Condition return the WebDriverElement once it is located, visible and clickable. */ public static function elementToBeClickable(WebDriverBy $by) { @@ -453,7 +449,7 @@ function (WebDriver $driver) use ($visibility_of_element_located) { * Wait until an element is no longer attached to the DOM. * * @param WebDriverElement $element The element to wait for. - * @return WebDriverExpectedCondition Condition returns whether the element is still attached to the DOM. + * @return static Condition returns whether the element is still attached to the DOM. */ public static function stalenessOf(WebDriverElement $element) { @@ -479,8 +475,7 @@ function () use ($element) { * the condition is checked. * * @param WebDriverExpectedCondition $condition The condition wrapped. - * @return WebDriverExpectedCondition Condition returns the return value of the getApply() of the given - * condition. + * @return static Condition returns the return value of the getApply() of the given condition. */ public static function refreshed(self $condition) { @@ -499,7 +494,7 @@ function (WebDriver $driver) use ($condition) { * An expectation for checking if the given element is selected. * * @param mixed $element_or_by Either the element or the locator. - * @return WebDriverExpectedCondition Condition returns whether the element is selected. + * @return static Condition returns whether the element is selected. */ public static function elementToBeSelected($element_or_by) { @@ -514,7 +509,7 @@ public static function elementToBeSelected($element_or_by) * * @param mixed $element_or_by Either the element or the locator. * @param bool $selected The required state. - * @return WebDriverExpectedCondition Condition returns whether the element is selected. + * @return static Condition returns whether the element is selected. */ public static function elementSelectionStateToBe($element_or_by, $selected) { @@ -544,8 +539,7 @@ function (WebDriver $driver) use ($element_or_by, $selected) { /** * An expectation for whether an alert() box is present. * - * @return WebDriverExpectedCondition Condition returns WebDriverAlert if alert() is present, - * null otherwise. + * @return static Condition returns WebDriverAlert if alert() is present, null otherwise. */ public static function alertIsPresent() { From 372fcba2b549a2f7a982e5eacb45614961dcddd5 Mon Sep 17 00:00:00 2001 From: Antonin Rykalsky Date: Mon, 12 Feb 2018 12:58:01 +0100 Subject: [PATCH 212/600] Disable sending Expect header in POST requests --- lib/Remote/HttpCommandExecutor.php | 6 +++++ .../ReportSauceLabsStatusListener.php | 2 ++ tests/unit/Remote/HttpCommandExecutorTest.php | 26 ++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 09bf000d0..6a795080c 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -263,6 +263,12 @@ public function execute(WebDriverCommand $command) curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method); } + if (in_array($http_method, ['POST', 'PUT'])) { + // Disable sending 'Expect: 100-Continue' header, as it is causing issues with eg. squid proxy + // https://tools.ietf.org/html/rfc7231#section-5.1.1 + curl_setopt($this->curl, CURLOPT_HTTPHEADER, ['Expect:']); + } + $encoded_params = null; if ($http_method === 'POST' && $params && is_array($params)) { diff --git a/tests/functional/ReportSauceLabsStatusListener.php b/tests/functional/ReportSauceLabsStatusListener.php index f2a3c9f7d..8d25b76ff 100644 --- a/tests/functional/ReportSauceLabsStatusListener.php +++ b/tests/functional/ReportSauceLabsStatusListener.php @@ -77,6 +77,8 @@ private function submitToSauceLabs($url, array $data) curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($curl, CURLOPT_USERPWD, getenv('SAUCE_USERNAME') . ':' . getenv('SAUCE_ACCESS_KEY')); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); + // Disable sending 'Expect: 100-Continue' header, as it is causing issues with eg. squid proxy + curl_setopt($curl, CURLOPT_HTTPHEADER, ['Expect:']); curl_exec($curl); diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php index a3810e731..5519fa0e4 100644 --- a/tests/unit/Remote/HttpCommandExecutorTest.php +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -34,19 +34,32 @@ public function setUp() * @dataProvider commandProvider * @param int $command * @param array $params + * @param bool $shouldResetExpectHeader * @param string $expectedUrl * @param string $expectedPostData */ - public function testShouldSendRequestToAssembledUrl($command, array $params, $expectedUrl, $expectedPostData) - { + public function testShouldSendRequestToAssembledUrl( + $command, + array $params, + $shouldResetExpectHeader, + $expectedUrl, + $expectedPostData + ) { $command = new WebDriverCommand('foo-123', $command, $params); $curlSetoptMock = $this->getFunctionMock(__NAMESPACE__, 'curl_setopt'); $curlSetoptMock->expects($this->at(0)) ->with($this->anything(), CURLOPT_URL, $expectedUrl); - $curlSetoptMock->expects($this->at(2)) - ->with($this->anything(), CURLOPT_POSTFIELDS, $expectedPostData); + if ($shouldResetExpectHeader) { + $curlSetoptMock->expects($this->at(2)) + ->with($this->anything(), CURLOPT_HTTPHEADER, ['Expect:']); + $curlSetoptMock->expects($this->at(3)) + ->with($this->anything(), CURLOPT_POSTFIELDS, $expectedPostData); + } else { + $curlSetoptMock->expects($this->at(2)) + ->with($this->anything(), CURLOPT_POSTFIELDS, $expectedPostData); + } $curlExecMock = $this->getFunctionMock(__NAMESPACE__, 'curl_exec'); $curlExecMock->expects($this->once()) @@ -64,30 +77,35 @@ public function commandProvider() 'POST command having :id placeholder in url' => [ DriverCommand::SEND_KEYS_TO_ELEMENT, ['value' => 'submitted-value', ':id' => '1337'], + true, 'http://localhost:4444/session/foo-123/element/1337/value', '{"value":"submitted-value"}', ], 'POST command without :id placeholder in url' => [ DriverCommand::TOUCH_UP, ['x' => 3, 'y' => 6], + true, 'http://localhost:4444/session/foo-123/touch/up', '{"x":3,"y":6}', ], 'Extra useless placeholder parameter should be removed' => [ DriverCommand::TOUCH_UP, ['x' => 3, 'y' => 6, ':useless' => 'foo'], + true, 'http://localhost:4444/session/foo-123/touch/up', '{"x":3,"y":6}', ], 'DELETE command' => [ DriverCommand::DELETE_COOKIE, [':name' => 'cookie-name'], + false, 'http://localhost:4444/session/foo-123/cookie/cookie-name', null, ], 'GET command without session in URL' => [ DriverCommand::GET_ALL_SESSIONS, [], + false, 'http://localhost:4444/sessions', null, ], From 42e7b6554f30689baf43827b791a678b2f7ecc8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 17 Feb 2018 01:19:28 +0000 Subject: [PATCH 213/600] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3adb0988..67969e3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Added - Connection and request timeouts could be specified also when creating RemoteWebDriver from existing session ID. +### Changed +- Disable sending 'Expect: 100-Continue' header with POST requests, as they may more easily fail when sending via eg. squid proxy. + ## 1.5.0 - 2017-11-15 ### Changed - Drop PHP 5.5 support, the minimal required version of PHP is now PHP 5.6. From 2d40e31c8911c4e0e9df43ca771623266bb978da Mon Sep 17 00:00:00 2001 From: Drew Budwin Date: Fri, 2 Feb 2018 18:37:19 -0500 Subject: [PATCH 214/600] Update PHPDoc for functions that return static instances of a class Previously, functions that contained functionality similar to `return new static(...)` had their `@return` PHPDoc tag to specify the class name like `@return SomeClass` where the preferred documentation should be `@return static`. Some support for this decision: https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#keyword https://netbeans.org/bugzilla/show_bug.cgi?id=196565 https://blog.madewithlove.be/post/return-types/ --- CHANGELOG.md | 1 + lib/Chrome/ChromeDriver.php | 3 +++ lib/Chrome/ChromeDriverService.php | 3 +++ lib/Remote/DesiredCapabilities.php | 24 ++++++++++---------- lib/Remote/RemoteWebDriver.php | 4 ++-- lib/Remote/RemoteWebElement.php | 2 +- lib/Support/Events/EventFiringWebElement.php | 2 +- lib/WebDriverBy.php | 16 ++++++------- lib/WebDriverExpectedCondition.php | 2 +- 9 files changed, 32 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3adb0988..0b7288a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased ### Added - Connection and request timeouts could be specified also when creating RemoteWebDriver from existing session ID. +- Update PHPDoc for functions that return static instances of a class. ## 1.5.0 - 2017-11-15 ### Changed diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 832ca17a8..107854b4a 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -24,6 +24,9 @@ class ChromeDriver extends RemoteWebDriver { + /** + * @return static + */ public static function start(DesiredCapabilities $desired_capabilities = null, ChromeDriverService $service = null) { if ($desired_capabilities === null) { diff --git a/lib/Chrome/ChromeDriverService.php b/lib/Chrome/ChromeDriverService.php index 90b3d24f7..c9525126d 100644 --- a/lib/Chrome/ChromeDriverService.php +++ b/lib/Chrome/ChromeDriverService.php @@ -22,6 +22,9 @@ class ChromeDriverService extends DriverService // The environment variable storing the path to the chrome driver executable. const CHROME_DRIVER_EXE_PROPERTY = 'webdriver.chrome.driver'; + /** + * @return static + */ public static function createDefaultService() { $exe = getenv(self::CHROME_DRIVER_EXE_PROPERTY); diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 940fcf98c..0e1a1ab25 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -178,7 +178,7 @@ public function toArray() } /** - * @return DesiredCapabilities + * @return static */ public static function android() { @@ -189,7 +189,7 @@ public static function android() } /** - * @return DesiredCapabilities + * @return static */ public static function chrome() { @@ -200,7 +200,7 @@ public static function chrome() } /** - * @return DesiredCapabilities + * @return static */ public static function firefox() { @@ -218,7 +218,7 @@ public static function firefox() } /** - * @return DesiredCapabilities + * @return static */ public static function htmlUnit() { @@ -229,7 +229,7 @@ public static function htmlUnit() } /** - * @return DesiredCapabilities + * @return static */ public static function htmlUnitWithJS() { @@ -242,7 +242,7 @@ public static function htmlUnitWithJS() } /** - * @return DesiredCapabilities + * @return static */ public static function internetExplorer() { @@ -253,7 +253,7 @@ public static function internetExplorer() } /** - * @return DesiredCapabilities + * @return static */ public static function microsoftEdge() { @@ -264,7 +264,7 @@ public static function microsoftEdge() } /** - * @return DesiredCapabilities + * @return static */ public static function iphone() { @@ -275,7 +275,7 @@ public static function iphone() } /** - * @return DesiredCapabilities + * @return static */ public static function ipad() { @@ -286,7 +286,7 @@ public static function ipad() } /** - * @return DesiredCapabilities + * @return static */ public static function opera() { @@ -297,7 +297,7 @@ public static function opera() } /** - * @return DesiredCapabilities + * @return static */ public static function safari() { @@ -308,7 +308,7 @@ public static function safari() } /** - * @return DesiredCapabilities + * @return static */ public static function phantomjs() { diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index becab6b98..1487689ec 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -87,7 +87,7 @@ protected function __construct( * @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through * @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through * @param DesiredCapabilities $required_capabilities The required capabilities - * @return RemoteWebDriver + * @return static */ public static function create( $selenium_server_url = 'http://localhost:4444/wd/hub', @@ -141,7 +141,7 @@ public static function create( * @param string $session_id The existing session id * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server - * @return RemoteWebDriver + * @return static */ public static function createBySessionID( $session_id, diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 17fa258c4..26936d8b9 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -408,7 +408,7 @@ public function equals(WebDriverElement $other) * * @param string $id * - * @return RemoteWebElement + * @return static */ protected function newElement($id) { diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php index 9595953cf..8df5cbb78 100644 --- a/lib/Support/Events/EventFiringWebElement.php +++ b/lib/Support/Events/EventFiringWebElement.php @@ -405,7 +405,7 @@ protected function dispatch($method, ...$arguments) /** * @param WebDriverElement $element - * @return EventFiringWebElement + * @return static */ protected function newElement(WebDriverElement $element) { diff --git a/lib/WebDriverBy.php b/lib/WebDriverBy.php index f882683b3..822a5c5fc 100644 --- a/lib/WebDriverBy.php +++ b/lib/WebDriverBy.php @@ -60,7 +60,7 @@ public function getValue() * names are not permitted. * * @param string $class_name - * @return WebDriverBy + * @return static */ public static function className($class_name) { @@ -71,7 +71,7 @@ public static function className($class_name) * Locates elements matching a CSS selector. * * @param string $css_selector - * @return WebDriverBy + * @return static */ public static function cssSelector($css_selector) { @@ -82,7 +82,7 @@ public static function cssSelector($css_selector) * Locates elements whose ID attribute matches the search value. * * @param string $id - * @return WebDriverBy + * @return static */ public static function id($id) { @@ -93,7 +93,7 @@ public static function id($id) * Locates elements whose NAME attribute matches the search value. * * @param string $name - * @return WebDriverBy + * @return static */ public static function name($name) { @@ -104,7 +104,7 @@ public static function name($name) * Locates anchor elements whose visible text matches the search value. * * @param string $link_text - * @return WebDriverBy + * @return static */ public static function linkText($link_text) { @@ -116,7 +116,7 @@ public static function linkText($link_text) * value. * * @param string $partial_link_text - * @return WebDriverBy + * @return static */ public static function partialLinkText($partial_link_text) { @@ -127,7 +127,7 @@ public static function partialLinkText($partial_link_text) * Locates elements whose tag name matches the search value. * * @param string $tag_name - * @return WebDriverBy + * @return static */ public static function tagName($tag_name) { @@ -138,7 +138,7 @@ public static function tagName($tag_name) * Locates elements matching an XPath expression. * * @param string $xpath - * @return WebDriverBy + * @return static */ public static function xpath($xpath) { diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 505474dfd..15c7b3d2d 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -564,7 +564,7 @@ function (WebDriver $driver) { * An expectation checking the number of opened windows. * * @param int $expectedNumberOfWindows - * @return WebDriverExpectedCondition + * @return static */ public static function numberOfWindowsToBe($expectedNumberOfWindows) { From c4dcacf1978e680573042823606a40c1f990dd3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 25 Feb 2018 17:45:57 +0000 Subject: [PATCH 215/600] Describe a bit more how to use php-webdriver with Firefox --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5b331d349..9bbb228c6 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,7 @@ Download and run that file, replacing # with the current server version. Keep in java -jar selenium-server-standalone-#.jar -When using Selenium server 3.5 and newer with some remote end clients (eg. Firefox with Geckodriver), you MUST disable so called "pass-through" mode, so that remote browser's protocol is translated to the protocol supported by php-webdriver (see [issue #469](https://github.com/facebook/php-webdriver/issues/469)): - - java -jar selenium-server-standalone-#.jar -enablePassThrough false +(Please see note below when using Firefox.) Then when you create a session, be sure to pass the url to where your server is running. @@ -58,6 +56,13 @@ $host = 'http://localhost:4444/wd/hub'; // this is the default Make sure to have latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases) installed. +Because Firefox (and Geckodriver) only supports new W3C WebDriver protocol (which is yet to be implemented by php-wedbriver - see [issue #469](https://github.com/facebook/php-webdriver/issues/469)), +the protocols must be translated by Selenium server - this feature is *partially* available in Selenium server version 3.5.0-3.8.1 and you can enable it like this: + + java -jar selenium-server-standalone-3.8.1.jar -enablePassThrough false + +Now you can start Firefox from your code: + ```php $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); ``` From a6d99922c0c9812ee4a663b5796be734b5a40257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 9 Mar 2018 11:10:25 +0100 Subject: [PATCH 216/600] Add missing required extensions to composer.json --- composer.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a96b82fe5..5e5fce576 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "symfony/process": "^2.8 || ^3.1 || ^4.0", "ext-curl": "*", "ext-zip": "*", - "ext-mbstring": "*" + "ext-mbstring": "*", + "ext-json": "*" }, "require-dev": { "phpunit/phpunit": "^5.7", @@ -28,6 +29,9 @@ "symfony/var-dumper": "^3.3 || ^4.0", "jakub-onderka/php-parallel-lint": "^0.9.2" }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, "autoload": { "psr-4": { "Facebook\\WebDriver\\": "lib/" From 17881d2832df05301185b3ae96081f25c484d12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 9 Mar 2018 11:13:31 +0100 Subject: [PATCH 217/600] Prefer Chrome in example script --- example.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/example.php b/example.php index 263d0c1d6..513b918b3 100644 --- a/example.php +++ b/example.php @@ -1,5 +1,6 @@ get('http://www.seleniumhq.org/'); +$driver->get('https://www.seleniumhq.org/'); // adding cookie $driver->manage()->deleteAllCookies(); @@ -57,5 +58,5 @@ ) ); -// close the Firefox +// close the browser $driver->quit(); From d4d655e958658eb0ab0050aea8f4d6c11f471c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 9 Mar 2018 11:28:50 +0100 Subject: [PATCH 218/600] Remove workaround for selenium bug https://github.com/SeleniumHQ/selenium/issues/3398 --- example.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/example.php b/example.php index 513b918b3..2a9d0b298 100644 --- a/example.php +++ b/example.php @@ -45,11 +45,8 @@ // write 'php' in the search box $driver->findElement(WebDriverBy::id('q')) - ->sendKeys('php'); - -// submit the form -$driver->findElement(WebDriverBy::id('submit')) - ->click(); // submit() does not work in Selenium 3 because of bug https://github.com/SeleniumHQ/selenium/issues/3398 + ->sendKeys('php') // fill the search box + ->submit(); // submit the whole form // wait at most 10 seconds until at least one result is shown $driver->wait(10)->until( From bc08cfaddb1bb1a1f25d1981c637b92fa9d3d6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 9 Mar 2018 11:38:17 +0100 Subject: [PATCH 219/600] Suggest Chrome on the first place in readme --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9bbb228c6..c0bd89d1f 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,14 @@ Then when you create a session, be sure to pass the url to where your server is $host = 'http://localhost:4444/wd/hub'; // this is the default ``` +##### Launch Chrome + +Make sure to have latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) installed. + +```php +$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); +``` + ##### Launch Firefox Make sure to have latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases) installed. @@ -67,14 +75,6 @@ Now you can start Firefox from your code: $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); ``` -##### Launch Chrome - -Make sure to have latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) installed. - -```php -$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); -``` - ##### You can also customize the desired capabilities ```php From 50be1fdd1d69119f7b6ad95f983a27b2b61f387b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 12 Mar 2018 16:34:11 +0100 Subject: [PATCH 220/600] PHPDoc: WebDriverElement::getAttribute may return null --- lib/WebDriverElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WebDriverElement.php b/lib/WebDriverElement.php index 2505368b3..7253cb238 100644 --- a/lib/WebDriverElement.php +++ b/lib/WebDriverElement.php @@ -38,7 +38,7 @@ public function click(); * Get the value of a the given attribute of the element. * * @param string $attribute_name The name of the attribute. - * @return string The value of the attribute. + * @return string|null The value of the attribute. */ public function getAttribute($attribute_name); From cb4696490461d95c80784eb8e45008a296663092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 13 Mar 2018 10:21:01 +0100 Subject: [PATCH 221/600] Remove useless parenthesis in WebDriverSelect (minor) --- lib/WebDriverSelect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WebDriverSelect.php b/lib/WebDriverSelect.php index abe6b54fe..1dfbe268b 100644 --- a/lib/WebDriverSelect.php +++ b/lib/WebDriverSelect.php @@ -39,7 +39,7 @@ public function __construct(WebDriverElement $element) } $this->element = $element; $value = $element->getAttribute('multiple'); - $this->isMulti = ($value === 'true'); + $this->isMulti = $value === 'true'; } public function isMultiple() From cbcc53cd9c53a1e3ea91947fac8a730b7dd39e8f Mon Sep 17 00:00:00 2001 From: Antonin Rykalsky Date: Tue, 13 Mar 2018 15:07:32 +0100 Subject: [PATCH 222/600] Fix other http headers being not sent in case of adding Except header --- lib/Remote/HttpCommandExecutor.php | 18 +++++++++--------- tests/unit/Remote/HttpCommandExecutorTest.php | 12 +++++++++++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 6a795080c..f584324b7 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -26,6 +26,11 @@ */ class HttpCommandExecutor implements WebDriverCommandExecutor { + const DEFAULT_HTTP_HEADERS = [ + 'Content-Type: application/json;charset=UTF-8', + 'Accept: application/json', + ]; + /** * @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference */ @@ -169,14 +174,7 @@ public function __construct($url, $http_proxy = null, $http_proxy_port = null) curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true); - curl_setopt( - $this->curl, - CURLOPT_HTTPHEADER, - [ - 'Content-Type: application/json;charset=UTF-8', - 'Accept: application/json', - ] - ); + curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS); $this->setRequestTimeout(30000); $this->setConnectionTimeout(30000); } @@ -266,7 +264,9 @@ public function execute(WebDriverCommand $command) if (in_array($http_method, ['POST', 'PUT'])) { // Disable sending 'Expect: 100-Continue' header, as it is causing issues with eg. squid proxy // https://tools.ietf.org/html/rfc7231#section-5.1.1 - curl_setopt($this->curl, CURLOPT_HTTPHEADER, ['Expect:']); + curl_setopt($this->curl, CURLOPT_HTTPHEADER, array_merge(static::DEFAULT_HTTP_HEADERS, ['Expect:'])); + } else { + curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS); } $encoded_params = null; diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php index 5519fa0e4..d6aae04b2 100644 --- a/tests/unit/Remote/HttpCommandExecutorTest.php +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -53,11 +53,21 @@ public function testShouldSendRequestToAssembledUrl( if ($shouldResetExpectHeader) { $curlSetoptMock->expects($this->at(2)) - ->with($this->anything(), CURLOPT_HTTPHEADER, ['Expect:']); + ->with( + $this->anything(), + CURLOPT_HTTPHEADER, + ['Content-Type: application/json;charset=UTF-8', 'Accept: application/json', 'Expect:'] + ); $curlSetoptMock->expects($this->at(3)) ->with($this->anything(), CURLOPT_POSTFIELDS, $expectedPostData); } else { $curlSetoptMock->expects($this->at(2)) + ->with( + $this->anything(), + CURLOPT_HTTPHEADER, + ['Content-Type: application/json;charset=UTF-8', 'Accept: application/json'] + ); + $curlSetoptMock->expects($this->at(3)) ->with($this->anything(), CURLOPT_POSTFIELDS, $expectedPostData); } From 8d368c65e6503aef11c545b1ec0cfb883b42b65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 14 Mar 2018 22:44:11 +0100 Subject: [PATCH 223/600] Add more php-cs-fixer rules --- .php_cs.dist | 5 +++++ tests/unit/Remote/DesiredCapabilitiesTest.php | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index d95f9d0fc..48aa29de7 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -12,6 +12,7 @@ return PhpCsFixer\Config::create() 'cast_spaces' => true, 'concat_space' => ['spacing' => 'one'], 'function_typehint_space' => true, + 'general_phpdoc_annotation_remove' => ['author'], 'linebreak_after_opening_tag' => true, 'lowercase_cast' => true, 'mb_str_functions' => true, @@ -50,6 +51,9 @@ return PhpCsFixer\Config::create() 'ordered_imports' => true, 'php_unit_construct' => true, 'php_unit_dedicate_assert' => true, + 'php_unit_expectation' => true, + 'php_unit_mock' => true, + 'php_unit_no_expectation_annotation' => true, 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_indent' => true, 'phpdoc_no_access' => true, @@ -73,6 +77,7 @@ return PhpCsFixer\Config::create() 'unary_operator_spaces' => true, 'visibility_required' => true, 'whitespace_after_comma_in_array' => true, + 'yoda_style' => false, ]) ->setRiskyAllowed(true) ->setFinder($finder); diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index 7d39c3675..6e14ef044 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -62,12 +62,11 @@ public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() $this->assertSame(333, $capabilities->getVersion()); } - /** - * @expectedException \Exception - * @expectedExceptionMessage isJavascriptEnabled() is a htmlunit-only option - */ public function testShouldNotAllowToDisableJavascriptForNonHtmlUnitBrowser() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('isJavascriptEnabled() is a htmlunit-only option'); + $capabilities = new DesiredCapabilities(); $capabilities->setBrowserName(WebDriverBrowserType::FIREFOX); $capabilities->setJavascriptEnabled(false); From 316dd0b7c056694a056bfc4e5217896eec2d1fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 14 Mar 2018 23:32:35 +0100 Subject: [PATCH 224/600] Use udiff format in php-cs-fixer for more readable diffs --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 5e5fce576..2a9929725 100644 --- a/composer.json +++ b/composer.json @@ -45,11 +45,11 @@ }, "scripts": { "codestyle:check": [ - "vendor/bin/php-cs-fixer fix --diff --dry-run", + "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff --dry-run -vvv --ansi", "vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/" ], "codestyle:fix": [ - "vendor/bin/php-cs-fixer fix --diff || exit 0", + "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff -vvv || exit 0", "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" ], "analyze": [ From 8a2df15749421bd6685b87c4574ad3c283d9d057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 16 Mar 2018 10:28:07 +0100 Subject: [PATCH 225/600] Fix @see in WebDriverOptions::addCookie --- lib/WebDriverOptions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index 9791b9f1c..a610a9e6a 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -37,7 +37,7 @@ public function __construct(ExecuteMethod $executor) /** * Add a specific cookie. * - * @see Facebook\WebDriver\Cookie for description of possible cookie properties + * @see Cookie for description of possible cookie properties * @param Cookie|array $cookie Cookie object. May be also created from array for compatibility reasons. * @return WebDriverOptions The current instance. */ From c95385adff0858e21446be5b49474056c1c06164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 16 Mar 2018 15:54:52 +0100 Subject: [PATCH 226/600] Fix the PHPDoc's types of Cookie.php --- lib/Cookie.php | 10 +++++----- lib/WebDriverOptions.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Cookie.php b/lib/Cookie.php index 0434a128b..57ec7e13a 100644 --- a/lib/Cookie.php +++ b/lib/Cookie.php @@ -104,7 +104,7 @@ public function setPath($path) } /** - * @return string + * @return string|null */ public function getPath() { @@ -126,7 +126,7 @@ public function setDomain($domain) } /** - * @return string + * @return string|null */ public function getDomain() { @@ -144,7 +144,7 @@ public function setExpiry($expiry) } /** - * @return int + * @return int|null */ public function getExpiry() { @@ -162,7 +162,7 @@ public function setSecure($secure) } /** - * @return bool + * @return bool|null */ public function isSecure() { @@ -180,7 +180,7 @@ public function setHttpOnly($httpOnly) } /** - * @return bool + * @return bool|null */ public function isHttpOnly() { diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index a610a9e6a..bec7fd18b 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -90,7 +90,7 @@ public function deleteCookieNamed($name) * Get the cookie with a given name. * * @param string $name - * @return Cookie The cookie, or null if no cookie with the given name is presented. + * @return Cookie|null The cookie, or null if no cookie with the given name is presented. */ public function getCookieNamed($name) { From 933a114472777c72f781166ce4bccd29d61abe7b Mon Sep 17 00:00:00 2001 From: agentFinland Date: Tue, 10 Apr 2018 12:13:13 -0700 Subject: [PATCH 227/600] Clarified README (#557) * Clarified README - simplified some word choice for those new to the project and non-primary English speakers - corrected grammar - removed unnecessary words (clutter) - corrected sentence fragments - corrected improper verb choices - added extra headers to clarify purpose of each set of steps - rearranged some sentences so the focus of the sentence came earlier and/or became the subject --- README.md | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c0bd89d1f..b25bee453 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ by the Selenium server and will also implement the [W3C WebDriver](https://w3c.g The concepts of this library are very similar to the "official" Java, .NET, Python and Ruby bindings from the [Selenium project](https://github.com/SeleniumHQ/selenium/). -**This is new version of PHP client, rewritten from scratch starting 2013.** +**As of 2013, this PHP client has been rewritten from scratch.** Using the old version? Check out [Adam Goucher's fork](https://github.com/Element-34/php-webdriver) of it. Looking for API documentation of php-webdriver? See [https://facebook.github.io/php-webdriver/](https://facebook.github.io/php-webdriver/latest/) -Any complaint, question, idea? You can post it on the user group https://www.facebook.com/groups/phpwebdriver/. +Any complaints, questions, or ideas? Post them in the user group https://www.facebook.com/groups/phpwebdriver/. ## Installation @@ -37,15 +37,19 @@ Then install the library: ## Getting started -All you need as the server for this client is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html +### Start Server -Download and run that file, replacing # with the current server version. Keep in mind you must have Java 8+ installed to start this command. +The required server is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html + +Download and run the server by replacing # with the current server version. Keep in mind **you must have Java 8+ installed to run this command**. java -jar selenium-server-standalone-#.jar -(Please see note below when using Firefox.) +**NOTE:** If using Firefox, see alternate command below. + +### Create a Browser Session -Then when you create a session, be sure to pass the url to where your server is running. +When creating a browser session, be sure to pass the url of your running server. ```php // This would be the url of the host running the server-standalone.jar @@ -54,7 +58,7 @@ $host = 'http://localhost:4444/wd/hub'; // this is the default ##### Launch Chrome -Make sure to have latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) installed. +Make sure to have latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) versions installed. ```php $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); @@ -64,8 +68,8 @@ $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); Make sure to have latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases) installed. -Because Firefox (and Geckodriver) only supports new W3C WebDriver protocol (which is yet to be implemented by php-wedbriver - see [issue #469](https://github.com/facebook/php-webdriver/issues/469)), -the protocols must be translated by Selenium server - this feature is *partially* available in Selenium server version 3.5.0-3.8.1 and you can enable it like this: +Because Firefox (and Geckodriver) only support the new W3C WebDriver protocol (which is yet to be implemented by php-webdriver - see [issue #469](https://github.com/facebook/php-webdriver/issues/469)), +the protocols must be translated by Selenium Server - this feature is *partially* available in Selenium Server versions 3.5.0-3.8.1 and you can enable it like this: java -jar selenium-server-standalone-3.8.1.jar -enablePassThrough false @@ -75,7 +79,7 @@ Now you can start Firefox from your code: $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); ``` -##### You can also customize the desired capabilities +### Customize Desired Capabilities ```php $desired_capabilities = DesiredCapabilities::firefox(); @@ -85,7 +89,7 @@ $driver = RemoteWebDriver::create($host, $desired_capabilities); * See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities for more details. -* Above snippets are not intended to be a working example by simply copy pasting. See [example.php](example.php) for working example. +**NOTE:** Above snippets are not intended to be a working example by simply copy-pasting. See [example.php](example.php) for working example. ## Changelog For latest changes see [CHANGELOG.md](CHANGELOG.md) file. @@ -98,22 +102,21 @@ You may also want to check out the Selenium [docs](http://docs.seleniumhq.org/do ## Testing framework integration -To take advantage of automatized testing you will most probably want to integrate php-webdriver to your testing framework. -There are some project already providing this: +To take advantage of automatized testing you may want to integrate php-webdriver to your testing framework. +There are some projects already providing this: -- [Steward](https://github.com/lmc-eu/steward) integrates php-webdriver directly to [PHPUnit](https://phpunit.de/), also providers parallelization. -- [Codeception](http://codeception.com) testing framework provides BDD-layer on top of php-webdriver in its [WebDriver module](http://codeception.com/docs/modules/WebDriver). -- You can also check out this [blogpost](http://codeception.com/11-12-2013/working-with-phpunit-and-selenium-webdriver.html) + [demo project](https://github.com/DavertMik/php-webdriver-demo), describing simple [PHPUnit](https://phpunit.de/) integration. +- [Steward](https://github.com/lmc-eu/steward) integrates php-webdriver directly to [PHPUnit](https://phpunit.de/), and provides parallelization +- [Codeception](http://codeception.com) testing framework provides BDD-layer on top of php-webdriver in its [WebDriver module](http://codeception.com/docs/modules/WebDriver) +- You can also check out this [blogpost](http://codeception.com/11-12-2013/working-with-phpunit-and-selenium-webdriver.html) + [demo project](https://github.com/DavertMik/php-webdriver-demo), describing simple [PHPUnit](https://phpunit.de/) integration ## Support -We have a great community willing to try and help you! +We have a great community willing to help you! -- **Via our Facebook Group** - If you have questions or are an active contributor consider joining our [facebook group](https://www.facebook.com/groups/phpwebdriver/) and contributing to the communal discussion and support. -- **Via StackOverflow** - You can also [ask a question](https://stackoverflow.com/questions/ask?tags=php+selenium-webdriver) or find many already answered question on StackOverflow. -- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/facebook/php-webdriver/issues/new) as an new issue. +- **Via our Facebook Group** - If you have questions or are an active contributor consider joining our [facebook group](https://www.facebook.com/groups/phpwebdriver/) and contribute to communal discussion and support +- **Via StackOverflow** - You can also [ask a question](https://stackoverflow.com/questions/ask?tags=php+selenium-webdriver) or find many already answered question on StackOverflow +- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/facebook/php-webdriver/issues/new) as an new issue ## Contributing -We love to have your help to make php-webdriver better. See [CONTRIBUTING.md](CONTRIBUTING.md) for more information -about contributing and developing php-webdriver. +We love to have your help to make php-webdriver better. See [CONTRIBUTING.md](CONTRIBUTING.md) for more information about contributing and developing php-webdriver. From f9a1a6ba4f57be77cc92122ae13df3dad6d3191e Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Wed, 16 May 2018 10:34:50 -0700 Subject: [PATCH 228/600] Update changelog for release --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b76cce76d..0f3088da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +--- + +## 1.6.0 - 2018-05-16 ### Added - Connection and request timeouts could be specified also when creating RemoteWebDriver from existing session ID. - Update PHPDoc for functions that return static instances of a class. From a1784b20ea64afdb0613e5164b3cb42773df4578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 28 May 2018 16:32:37 +0200 Subject: [PATCH 229/600] Update Selenium to 3.8.1 and Chromedriver to 2.38 --- .travis.yml | 6 +++--- tests/functional/RemoteWebDriverTest.php | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c9c5c1a3..4a2cada83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: global: - DISPLAY=:99.0 - BROWSER_NAME="htmlunit" - - CHROMEDRIVER_VERSION="2.35" + - CHROMEDRIVER_VERSION="2.38" matrix: include: @@ -93,8 +93,8 @@ before_script: - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - sh -e /etc/init.d/xvfb start - - if [ ! -f jar/selenium-server-standalone-3.4.0.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.4/selenium-server-standalone-3.4.0.jar; fi - - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.4.0.jar -log ./logs/selenium.log & + - if [ ! -f jar/selenium-server-standalone-3.8.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; fi + - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.8.1.jar -enablePassThrough false -log ./logs/selenium.log & - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 440776ad5..818a9da5a 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -84,7 +84,6 @@ public function testShouldGetAllSessions() $this->assertArrayHasKey('capabilities', $sessions[0]); $this->assertArrayHasKey('id', $sessions[0]); - $this->assertArrayHasKey('class', $sessions[0]); } /** From 6c885357678c692ee76d97d21ba03fbfbd19b46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 29 May 2018 15:03:45 +0200 Subject: [PATCH 230/600] Add utility classes to interact with checkboxes and radio buttons (#545) * Add an utility class to manipulate checkboxes and radio buttons --- lib/AbstractWebDriverCheckboxOrRadio.php | 248 ++++++++++++++++++ lib/WebDriverCheckboxes.php | 66 +++++ lib/WebDriverRadios.php | 65 +++++ tests/functional/WebDriverCheckboxesTest.php | 197 ++++++++++++++ tests/functional/WebDriverRadiosTest.php | 184 +++++++++++++ tests/functional/web/form_checkbox_radio.html | 43 +++ 6 files changed, 803 insertions(+) create mode 100644 lib/AbstractWebDriverCheckboxOrRadio.php create mode 100644 lib/WebDriverCheckboxes.php create mode 100644 lib/WebDriverRadios.php create mode 100644 tests/functional/WebDriverCheckboxesTest.php create mode 100644 tests/functional/WebDriverRadiosTest.php create mode 100644 tests/functional/web/form_checkbox_radio.html diff --git a/lib/AbstractWebDriverCheckboxOrRadio.php b/lib/AbstractWebDriverCheckboxOrRadio.php new file mode 100644 index 000000000..46288592b --- /dev/null +++ b/lib/AbstractWebDriverCheckboxOrRadio.php @@ -0,0 +1,248 @@ +getTagName(); + if ($tagName !== 'input') { + throw new UnexpectedTagNameException('input', $tagName); + } + + $this->name = $element->getAttribute('name'); + if ($this->name === null) { + throw new WebDriverException('The input does not have a "name" attribute.'); + } + + $this->element = $element; + } + + public function getOptions() + { + return $this->getRelatedElements(); + } + + public function getAllSelectedOptions() + { + $selectedElement = []; + foreach ($this->getRelatedElements() as $element) { + if ($element->isSelected()) { + $selectedElement[] = $element; + + if (!$this->isMultiple()) { + return $selectedElement; + } + } + } + + return $selectedElement; + } + + public function getFirstSelectedOption() + { + foreach ($this->getRelatedElements() as $element) { + if ($element->isSelected()) { + return $element; + } + } + + throw new NoSuchElementException( + sprintf('No %s are selected', 'radio' === $this->type ? 'radio buttons' : 'checkboxes') + ); + } + + public function selectByIndex($index) + { + $this->byIndex($index); + } + + public function selectByValue($value) + { + $this->byValue($value); + } + + public function selectByVisibleText($text) + { + $this->byVisibleText($text); + } + + public function selectByVisiblePartialText($text) + { + $this->byVisibleText($text, true); + } + + /** + * Selects or deselects a checkbox or a radio button by its value. + * + * @param string $value + * @param bool $select + * @throws NoSuchElementException + */ + protected function byValue($value, $select = true) + { + $matched = false; + foreach ($this->getRelatedElements($value) as $element) { + $select ? $this->selectOption($element) : $this->deselectOption($element); + if (!$this->isMultiple()) { + return; + } + + $matched = true; + } + + if (!$matched) { + throw new NoSuchElementException( + sprintf('Cannot locate %s with value: %s', $this->type, $value) + ); + } + } + + /** + * Selects or deselects a checkbox or a radio button by its index. + * + * @param int $index + * @param bool $select + * @throws NoSuchElementException + */ + protected function byIndex($index, $select = true) + { + $elements = $this->getRelatedElements(); + if (!isset($elements[$index])) { + throw new NoSuchElementException(sprintf('Cannot locate %s with index: %d', $this->type, $index)); + } + + $select ? $this->selectOption($elements[$index]) : $this->deselectOption($elements[$index]); + } + + /** + * Selects or deselects a checkbox or a radio button by its visible text. + * + * @param string $text + * @param bool $partial + * @param bool $select + */ + protected function byVisibleText($text, $partial = false, $select = true) + { + foreach ($this->getRelatedElements() as $element) { + $normalizeFilter = sprintf( + $partial ? 'contains(normalize-space(.), %s)' : 'normalize-space(.) = %s', + XPathEscaper::escapeQuotes($text) + ); + + $xpath = 'ancestor::label'; + $xpathNormalize = sprintf('%s[%s]', $xpath, $normalizeFilter); + + $id = $element->getAttribute('id'); + if ($id !== null) { + $idFilter = sprintf('@for = %s', XPathEscaper::escapeQuotes($id)); + + $xpath .= sprintf(' | //label[%s]', $idFilter); + $xpathNormalize .= sprintf(' | //label[%s and %s]', $idFilter, $normalizeFilter); + } + + try { + $element->findElement(WebDriverBy::xpath($xpathNormalize)); + } catch (NoSuchElementException $e) { + if ($partial) { + continue; + } + + try { + // Since the mechanism of getting the text in xpath is not the same as + // webdriver, use the expensive getText() to check if nothing is matched. + if ($text !== $element->findElement(WebDriverBy::xpath($xpath))->getText()) { + continue; + } + } catch (NoSuchElementException $e) { + continue; + } + } + + $select ? $this->selectOption($element) : $this->deselectOption($element); + if (!$this->isMultiple()) { + return; + } + } + } + + /** + * Gets checkboxes or radio buttons with the same name. + * + * @param string|null $value + * @return WebDriverElement[] + */ + protected function getRelatedElements($value = null) + { + $valueSelector = $value ? sprintf(' and @value = %s', XPathEscaper::escapeQuotes($value)) : ''; + $formId = $this->element->getAttribute('form'); + if ($formId === null) { + $form = $this->element->findElement(WebDriverBy::xpath('ancestor::form')); + + $formId = $form->getAttribute('id'); + if ($formId === '') { + return $form->findElements(WebDriverBy::xpath( + sprintf('.//input[@name = %s%s]', XPathEscaper::escapeQuotes($this->name), $valueSelector) + )); + } + } + + return $this->element->findElements(WebDriverBy::xpath(sprintf( + '//form[@id = %1$s]//input[@name = %2$s%3$s] | //input[@form = %1$s and @name = %2$s%3$s]', + XPathEscaper::escapeQuotes($formId), + XPathEscaper::escapeQuotes($this->name), + $valueSelector + ))); + } + + /** + * Selects a checkbox or a radio button. + */ + protected function selectOption(WebDriverElement $element) + { + if (!$element->isSelected()) { + $element->click(); + } + } + + /** + * Deselects a checkbox or a radio button. + */ + protected function deselectOption(WebDriverElement $element) + { + if ($element->isSelected()) { + $element->click(); + } + } +} diff --git a/lib/WebDriverCheckboxes.php b/lib/WebDriverCheckboxes.php new file mode 100644 index 000000000..1ac00093d --- /dev/null +++ b/lib/WebDriverCheckboxes.php @@ -0,0 +1,66 @@ +type = $element->getAttribute('type'); + if ($this->type !== 'checkbox') { + throw new WebDriverException('The input must be of type "checkbox".'); + } + } + + public function isMultiple() + { + return true; + } + + public function deselectAll() + { + foreach ($this->getRelatedElements() as $checkbox) { + $this->deselectOption($checkbox); + } + } + + public function deselectByIndex($index) + { + $this->byIndex($index, false); + } + + public function deselectByValue($value) + { + $this->byValue($value, false); + } + + public function deselectByVisibleText($text) + { + $this->byVisibleText($text, false, false); + } + + public function deselectByVisiblePartialText($text) + { + $this->byVisibleText($text, true, false); + } +} diff --git a/lib/WebDriverRadios.php b/lib/WebDriverRadios.php new file mode 100644 index 000000000..d6a4d2ac7 --- /dev/null +++ b/lib/WebDriverRadios.php @@ -0,0 +1,65 @@ +type = $element->getAttribute('type'); + if ($this->type !== 'radio') { + throw new WebDriverException('The input must be of type "radio".'); + } + } + + public function isMultiple() + { + return false; + } + + public function deselectAll() + { + throw new UnsupportedOperationException('You cannot deselect radio buttons'); + } + + public function deselectByIndex($index) + { + throw new UnsupportedOperationException('You cannot deselect radio buttons'); + } + + public function deselectByValue($value) + { + throw new UnsupportedOperationException('You cannot deselect radio buttons'); + } + + public function deselectByVisibleText($text) + { + throw new UnsupportedOperationException('You cannot deselect radio buttons'); + } + + public function deselectByVisiblePartialText($text) + { + throw new UnsupportedOperationException('You cannot deselect radio buttons'); + } +} diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php new file mode 100644 index 000000000..3bf8ccffd --- /dev/null +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -0,0 +1,197 @@ +driver->get($this->getTestPageUrl('form_checkbox_radio.html')); + } + + public function testIsMultiple() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $this->assertTrue($c->isMultiple()); + } + + public function testGetOptions() + { + $c = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//form[2]//input[@type="checkbox"]')) + ); + $this->assertNotEmpty($c->getOptions()); + } + + public function testGetFirstSelectedOption() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $c->selectByValue('j2a'); + $this->assertSame('j2a', $c->getFirstSelectedOption()->getAttribute('value')); + } + + public function testSelectByValue() + { + $selectedOptions = ['j2b', 'j2c']; + + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + foreach ($selectedOptions as $index => $selectedOption) { + $c->selectByValue($selectedOption); + } + + $selectedValues = []; + foreach ($c->getAllSelectedOptions() as $option) { + $selectedValues[] = $option->getAttribute('value'); + } + $this->assertSame($selectedOptions, $selectedValues); + } + + public function testSelectByValueInvalid() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate checkbox with value: notexist'); + $c->selectByValue('notexist'); + } + + public function testSelectByIndex() + { + $selectedOptions = [1 => 'j2b', 2 => 'j2c']; + + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + foreach ($selectedOptions as $index => $selectedOption) { + $c->selectByIndex($index); + } + + $selectedValues = []; + foreach ($c->getAllSelectedOptions() as $option) { + $selectedValues[] = $option->getAttribute('value'); + } + $this->assertSame(array_values($selectedOptions), $selectedValues); + } + + public function testSelectByIndexInvalid() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate checkbox with index: ' . PHP_INT_MAX); + $c->selectByIndex(PHP_INT_MAX); + } + + /** + * @dataProvider selectByVisibleTextDataProvider + * + * @param string $text + * @param string $value + */ + public function testSelectByVisibleText($text, $value) + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $c->selectByVisibleText($text); + $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + } + + /** + * @return array + */ + public function selectByVisibleTextDataProvider() + { + return [ + ['J 2 B', 'j2b'], + ['J2C', 'j2c'], + ]; + } + + /** + * @dataProvider selectByVisiblePartialTextDataProvider + * + * @param string $text + * @param string $value + */ + public function testSelectByVisiblePartialText($text, $value) + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $c->selectByVisiblePartialText($text); + $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + } + + /** + * @return array + */ + public function selectByVisiblePartialTextDataProvider() + { + return [ + ['2 B', 'j2b'], + ['2C', 'j2c'], + ]; + } + + public function testDeselectAll() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $c->selectByIndex(0); + $this->assertCount(1, $c->getAllSelectedOptions()); + $c->deselectAll(); + $this->assertEmpty($c->getAllSelectedOptions()); + } + + public function testDeselectByIndex() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $c->selectByIndex(0); + $this->assertCount(1, $c->getAllSelectedOptions()); + $c->deselectByIndex(0); + $this->assertEmpty($c->getAllSelectedOptions()); + } + + public function testDeselectByValue() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $c->selectByValue('j2a'); + $this->assertCount(1, $c->getAllSelectedOptions()); + $c->deselectByValue('j2a'); + $this->assertEmpty($c->getAllSelectedOptions()); + } + + public function testDeselectByVisibleText() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $c->selectByVisibleText('J 2 B'); + $this->assertCount(1, $c->getAllSelectedOptions()); + $c->deselectByVisibleText('J 2 B'); + $this->assertEmpty($c->getAllSelectedOptions()); + } + + public function testDeselectByVisiblePartialText() + { + $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + + $c->selectByVisiblePartialText('2C'); + $this->assertCount(1, $c->getAllSelectedOptions()); + $c->deselectByVisiblePartialText('2C'); + $this->assertEmpty($c->getAllSelectedOptions()); + } +} diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php new file mode 100644 index 000000000..f28417ac4 --- /dev/null +++ b/tests/functional/WebDriverRadiosTest.php @@ -0,0 +1,184 @@ +driver->get($this->getTestPageUrl('form_checkbox_radio.html')); + } + + public function testIsMultiple() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $this->assertFalse($c->isMultiple()); + } + + public function testGetOptions() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $values = []; + foreach ($c->getOptions() as $option) { + $values[] = $option->getAttribute('value'); + } + + $this->assertSame(['j3a', 'j3b', 'j3c'], $values); + } + + public function testGetFirstSelectedOption() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $c->selectByValue('j3a'); + $this->assertSame('j3a', $c->getFirstSelectedOption()->getAttribute('value')); + } + + public function testSelectByValue() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $c->selectByValue('j3b'); + + $selectedOptions = $c->getAllSelectedOptions(); + $this->assertCount(1, $selectedOptions); + $this->assertSame('j3b', $selectedOptions[0]->getAttribute('value')); + } + + public function testSelectByValueInvalid() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate radio with value: notexist'); + $c->selectByValue('notexist'); + } + + public function testSelectByIndex() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $c->selectByIndex(1); + + $allSelectedOptions = $c->getAllSelectedOptions(); + $this->assertCount(1, $allSelectedOptions); + $this->assertSame('j3b', $allSelectedOptions[0]->getAttribute('value')); + } + + public function testSelectByIndexInvalid() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(NoSuchElementException::class); + $this->expectExceptionMessage('Cannot locate radio with index: ' . PHP_INT_MAX); + $c->selectByIndex(PHP_INT_MAX); + } + + /** + * @dataProvider selectByVisibleTextDataProvider + * + * @param string $text + * @param string $value + */ + public function testSelectByVisibleText($text, $value) + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $c->selectByVisibleText($text); + $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + } + + /** + * @return array + */ + public function selectByVisibleTextDataProvider() + { + return [ + ['J 3 B', 'j3b'], + ['J3C', 'j3c'], + ]; + } + + /** + * @dataProvider selectByVisiblePartialTextDataProvider + * + * @param string $text + * @param string $value + */ + public function testSelectByVisiblePartialText($text, $value) + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $c->selectByVisiblePartialText($text); + $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + } + + /** + * @return array + */ + public function selectByVisiblePartialTextDataProvider() + { + return [ + ['3 B', 'j3b'], + ['3C', 'j3c'], + ]; + } + + public function testDeselectAllRadio() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You cannot deselect radio buttons'); + $c->deselectAll(); + } + + public function testDeselectByIndexRadio() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You cannot deselect radio buttons'); + $c->deselectByIndex(0); + } + + public function testDeselectByValueRadio() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You cannot deselect radio buttons'); + $c->deselectByValue('val'); + } + + public function testDeselectByVisibleTextRadio() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You cannot deselect radio buttons'); + $c->deselectByVisibleText('AB'); + } + + public function testDeselectByVisiblePartialTextRadio() + { + $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('You cannot deselect radio buttons'); + $c->deselectByVisiblePartialText('AB'); + } +} diff --git a/tests/functional/web/form_checkbox_radio.html b/tests/functional/web/form_checkbox_radio.html new file mode 100644 index 000000000..b51dcfe47 --- /dev/null +++ b/tests/functional/web/form_checkbox_radio.html @@ -0,0 +1,43 @@ + + + + + Form + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + From ce44465b74b1707a7e76b4f70f7d2fee6014ce94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 29 May 2018 15:17:26 +0200 Subject: [PATCH 231/600] Update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f3088da9..95a4c6c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased - ---- +### Added +- `WebDriverCheckboxes` and `WebDriverRadios` helper classes to simplify interaction with checkboxes and radio buttons. ## 1.6.0 - 2018-05-16 ### Added From 37c7b04a453d88d79e41e8ac4425603a04d17fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 16 Jun 2018 14:26:38 +0200 Subject: [PATCH 232/600] Fix the name of a env var in CONTRIBUTING.md (#583) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d7b93736c..1a01c7adb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,7 +42,7 @@ test suite: ./vendor/bin/phpunit --testsuite functional The functional tests will be started in HtmlUnit headless browser by default. If you want to run them in eg. Firefox, -simply set the `BROWSER` environment variable: +simply set the `BROWSER_NAME` environment variable: ... export BROWSER_NAME="firefox" From be2985897851adca3e941d8c07c28512e24ee4a1 Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Thu, 18 Oct 2018 13:53:38 -0700 Subject: [PATCH 233/600] Renamed license file. --- LICENCE.md => LICENSE.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENCE.md => LICENSE.md (100%) diff --git a/LICENCE.md b/LICENSE.md similarity index 100% rename from LICENCE.md rename to LICENSE.md From e020ae2811098d55cce705c66c52f1a4fbf2f9df Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Thu, 18 Oct 2018 13:58:23 -0700 Subject: [PATCH 234/600] Added copyright headers to 2 codefiles --- example.php | 14 ++++++++++++++ tests/bootstrap.php | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/example.php b/example.php index 2a9d0b298..f1109ed54 100644 --- a/example.php +++ b/example.php @@ -1,4 +1,18 @@ Date: Thu, 18 Oct 2018 14:14:22 -0700 Subject: [PATCH 235/600] Added a few more copyright headers. --- lib/Exception/IndexOutOfBoundsException.php | 13 +++++++++++++ lib/Exception/NoCollectionException.php | 13 +++++++++++++ lib/Exception/NoStringException.php | 13 +++++++++++++ lib/WebDriverSelectInterface.php | 13 +++++++++++++ tests/functional/web/slow_pixel.png.php | 13 +++++++++++++ tests/functional/web/submit.php | 16 +++++++++++++++- tests/functional/web/upload.php | 16 +++++++++++++++- 7 files changed, 95 insertions(+), 2 deletions(-) diff --git a/lib/Exception/IndexOutOfBoundsException.php b/lib/Exception/IndexOutOfBoundsException.php index ad52d21e9..de166b61e 100644 --- a/lib/Exception/IndexOutOfBoundsException.php +++ b/lib/Exception/IndexOutOfBoundsException.php @@ -1,4 +1,17 @@ + diff --git a/tests/functional/web/upload.php b/tests/functional/web/upload.php index 91a61bbcf..0bac36c3a 100644 --- a/tests/functional/web/upload.php +++ b/tests/functional/web/upload.php @@ -1,4 +1,18 @@ - + From 799fc83fb9bb0f61bfcb725db336a955774c22c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 6 Jun 2019 18:10:13 +0200 Subject: [PATCH 236/600] Improve test stability on SauceLabs; simplify doubleClick test to make it temporarily, as this action is not part of W3C WebDriver --- .travis.yml | 2 +- tests/functional/RemoteWebDriverTest.php | 26 +++++++++++++++------- tests/functional/WebDriverActionsTest.php | 5 +---- tests/functional/WebDriverTestCase.php | 4 ++-- tests/functional/WebDriverTimeoutsTest.php | 4 ++-- tests/functional/web/delayed_element.html | 2 +- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4a2cada83..a268f0b4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,7 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - php: 7.2 - env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="15.15063" PLATFORM="Windows 10" + env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="16.16299" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 818a9da5a..d996d304a 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -145,6 +145,7 @@ public function testShouldCloseWindow() /** * @covers ::executeScript + * @group exclude-saucelabs */ public function testShouldExecuteScriptAndDoNotBlockExecution() { @@ -153,17 +154,18 @@ public function testShouldExecuteScriptAndDoNotBlockExecution() $element = $this->driver->findElement(WebDriverBy::id('id_test')); $this->assertSame('Test by ID', $element->getText()); + $start = microtime(true); $this->driver->executeScript(' setTimeout( - function(){document.getElementById("id_test").innerHTML = "Text changed by script"}, - 500 + function(){document.getElementById("id_test").innerHTML = "Text changed by script";}, + 250 )'); + $end = microtime(true); - // Make sure the script don't block the test execution - $this->assertSame('Test by ID', $element->getText()); + $this->assertLessThan(250, $end - $start, 'executeScript() should not block execution'); - // If we wait, the script should be executed - usleep(1000000); // wait 1000 ms + // If we wait, the script should be executed and its value changed + usleep(300000); // wait 300 ms $this->assertSame('Text changed by script', $element->getText()); } @@ -180,6 +182,7 @@ public function testShouldExecuteAsyncScriptAndWaitUntilItIsFinished() $element = $this->driver->findElement(WebDriverBy::id('id_test')); $this->assertSame('Test by ID', $element->getText()); + $start = microtime(true); $this->driver->executeAsyncScript( 'var callback = arguments[arguments.length - 1]; setTimeout( @@ -190,6 +193,13 @@ function(){ 250 );' ); + $end = microtime(true); + + $this->assertGreaterThan( + 0.250, + $end - $start, + 'executeAsyncScript() should block execution until callback() is called' + ); // The result must be immediately available, as the executeAsyncScript should block the execution until the // callback is called. @@ -204,7 +214,7 @@ public function testShouldTakeScreenshot() if (!extension_loaded('gd')) { $this->markTestSkipped('GD extension must be enabled'); } - if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { $this->markTestSkipped('Screenshots are not supported by HtmlUnit browser'); } @@ -227,7 +237,7 @@ public function testShouldSaveScreenshotToFile() if (!extension_loaded('gd')) { $this->markTestSkipped('GD extension must be enabled'); } - if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { $this->markTestSkipped('Screenshots are not supported by HtmlUnit browser'); } diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 188c76cd9..3df984810 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -122,10 +122,7 @@ public function testShouldDoubleClickOnElement() ->doubleClick($element) ->perform(); - $this->assertSame( - ['mouseover item-3', 'mousedown item-3', 'mouseup item-3', 'click item-3', 'dblclick item-3'], - $this->retrieveLoggedEvents() - ); + $this->assertContains('dblclick item-3', $this->retrieveLoggedEvents()); } /** diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index e9714a87c..5fe6a7e8a 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -44,7 +44,7 @@ protected function setUp() { $this->desiredCapabilities = new DesiredCapabilities(); - if ($this->isSauceLabsBuild()) { + if (static::isSauceLabsBuild()) { $this->setUpSauceLabs(); } else { if (getenv('BROWSER_NAME')) { @@ -87,7 +87,7 @@ protected function tearDown() /** * @return bool */ - public function isSauceLabsBuild() + public static function isSauceLabsBuild() { return getenv('SAUCELABS') ? true : false; } diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index 69d143cc4..733be545c 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -42,7 +42,7 @@ public function testShouldGetDelayedElementWithImplicitWait() { $this->driver->get($this->getTestPageUrl('delayed_element.html')); - $this->driver->manage()->timeouts()->implicitlyWait(1); + $this->driver->manage()->timeouts()->implicitlyWait(2); $element = $this->driver->findElement(WebDriverBy::id('delayed')); $this->assertInstanceOf(RemoteWebElement::class, $element); @@ -54,7 +54,7 @@ public function testShouldGetDelayedElementWithImplicitWait() */ public function testShouldFailIfPageIsLoadingLongerThanPageLoadTimeout() { - if ($this->desiredCapabilities->getBrowserName() == WebDriverBrowserType::HTMLUNIT) { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { $this->markTestSkipped('Not supported by HtmlUnit browser'); } diff --git a/tests/functional/web/delayed_element.html b/tests/functional/web/delayed_element.html index b0f057a9a..4572cd342 100644 --- a/tests/functional/web/delayed_element.html +++ b/tests/functional/web/delayed_element.html @@ -12,7 +12,7 @@ setTimeout(function () { var wrapper = document.getElementById("wrapper"); wrapper.innerHTML = '
    Element appearing after 500ms
    '; - }, 500); + }, 1500); From 6d488eacd23db77822a748725a1c9dafa6d0221e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 8 Jun 2019 12:33:18 +0200 Subject: [PATCH 237/600] Force Chrome 74 on saucelabs, as 75 uses W3C protocol by default --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a268f0b4d..c97b22525 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,7 +49,7 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - php: 7.2 - env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" + env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" From 5f7a311bde888283615e8b3767a92302c5e29515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 7 Jun 2019 17:29:22 +0200 Subject: [PATCH 238/600] Use PHP 7.3 as the main PHP version for travis builds --- .travis.yml | 55 +++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index c97b22525..082a6efb8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,11 @@ sudo: false dist: trusty php: - - 5.6 - - 7.0 - - 7.1 - - 7.2 + - '5.6' + - '7.0' + - '7.1' + - '7.2' + - '7.3' env: global: @@ -16,30 +17,43 @@ env: matrix: include: + # Codestyle check build + - php: '7.3' + env: CHECK_CODESTYLE=1 + before_install: + - phpenv config-rm xdebug.ini + before_script: ~ + script: + - composer require phpstan/phpstan-shim # Not part of require-dev, because it won't install on PHP 5.6 + - composer analyze + - composer codestyle:check + after_script: ~ + after_success: ~ + + # Build with lowest possible dependencies on lowest possible PHP + - php: '5.6' + env: DEPENDENCIES="--prefer-lowest" + # Add build to run tests against Firefox inside Travis environment - - php: 7.2 + - php: '7.3' env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" # Add build to run tests against Chrome inside Travis environment - - php: 7.2 + - php: '7.3' env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" addons: chrome: stable - # Build with lowest possible dependencies - - php: 7.2 - env: DEPENDENCIES="--prefer-lowest" - # Chrome on Travis build with lowest possible dependencies - - php: 7.2 + - php: '7.3' env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" DEPENDENCIES="--prefer-lowest" addons: chrome: stable # Saucelabs builds - - php: 7.2 + - php: '7.3' env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -48,7 +62,7 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: 7.2 + - php: '7.3' env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -57,7 +71,7 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: 7.2 + - php: '7.3' env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="16.16299" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & @@ -67,19 +81,6 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - # Codestyle check build - - php: 7.2 - env: CHECK_CODESTYLE=1 - before_install: - - phpenv config-rm xdebug.ini - before_script: ~ - script: - - composer require phpstan/phpstan-shim # Not part of require-dev, because it won't install on PHP 5.6 - - composer analyze - - composer codestyle:check - after_script: ~ - after_success: ~ - cache: directories: - $HOME/.composer/cache From 242fffeb4caf279a87f75a01b29a87e66a3e1a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 8 Jun 2019 15:02:51 +0200 Subject: [PATCH 239/600] Disable WebDriverSelectTest on saucelabs - it is too slow and has minimal value --- tests/functional/WebDriverCheckboxesTest.php | 4 ++++ tests/functional/WebDriverRadiosTest.php | 4 ++++ tests/functional/WebDriverSelectTest.php | 1 + 3 files changed, 9 insertions(+) diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php index 3bf8ccffd..128d298d5 100644 --- a/tests/functional/WebDriverCheckboxesTest.php +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -17,6 +17,10 @@ use Facebook\WebDriver\Exception\NoSuchElementException; +/** + * @covers \Facebook\WebDriver\WebDriverCheckboxes + * @covers \Facebook\WebDriver\AbstractWebDriverCheckboxOrRadio + */ class WebDriverCheckboxesTest extends WebDriverTestCase { protected function setUp() diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php index f28417ac4..2a1a9869d 100644 --- a/tests/functional/WebDriverRadiosTest.php +++ b/tests/functional/WebDriverRadiosTest.php @@ -18,6 +18,10 @@ use Facebook\WebDriver\Exception\NoSuchElementException; use Facebook\WebDriver\Exception\UnsupportedOperationException; +/** + * @covers \Facebook\WebDriver\WebDriverRadios + * @covers \Facebook\WebDriver\AbstractWebDriverCheckboxOrRadio + */ class WebDriverRadiosTest extends WebDriverTestCase { protected function setUp() diff --git a/tests/functional/WebDriverSelectTest.php b/tests/functional/WebDriverSelectTest.php index 37ad416af..b25dd03af 100644 --- a/tests/functional/WebDriverSelectTest.php +++ b/tests/functional/WebDriverSelectTest.php @@ -20,6 +20,7 @@ use Facebook\WebDriver\Exception\UnsupportedOperationException; /** + * @group exclude-saucelabs * @covers \Facebook\WebDriver\WebDriverSelect * @covers \Facebook\WebDriver\Exception\UnexpectedTagNameException */ From 9be6cbbd8006a24fb180df75cb4b9796a2aad770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 8 Jun 2019 15:42:49 +0200 Subject: [PATCH 240/600] Remove mostly redundant second lowest-deps build --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 082a6efb8..b3ee784e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,12 +46,6 @@ matrix: addons: chrome: stable - # Chrome on Travis build with lowest possible dependencies - - php: '7.3' - env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" DEPENDENCIES="--prefer-lowest" - addons: - chrome: stable - # Saucelabs builds - php: '7.3' env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" From 0f3933c41606fd076d79ff064bc0def2b774e67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 8 Jun 2019 22:50:56 +0200 Subject: [PATCH 241/600] Disable default W3C protocol in Chrome 75+ --- .travis.yml | 27 ++++++++++++++++++++++----- lib/Remote/HttpCommandExecutor.php | 5 +++++ lib/Remote/RemoteWebDriver.php | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3ee784e8..b6850baf1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,6 @@ env: global: - DISPLAY=:99.0 - BROWSER_NAME="htmlunit" - - CHROMEDRIVER_VERSION="2.38" matrix: include: @@ -34,15 +33,21 @@ matrix: - php: '5.6' env: DEPENDENCIES="--prefer-lowest" - # Add build to run tests against Firefox inside Travis environment + # Firefox inside Travis environment - php: '7.3' env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" - # Add build to run tests against Chrome inside Travis environment + # Stable Chrome + Chromedriver 74 inside Travis environment - php: '7.3' - env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" + env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" CHROMEDRIVER_VERSION="74.0.3729.6" + addons: + chrome: stable + + # Stable Chrome + Chromedriver 75+ inside Travis environment + - php: '7.3' + env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" CHROMEDRIVER_VERSION="75.0.3770.8" addons: chrome: stable @@ -56,8 +61,9 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" + env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" # 74 is the last version which don't use W3C WebDriver by default before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" @@ -65,6 +71,17 @@ matrix: sauce_connect: true jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + + - php: '7.3' + env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="75.0" PLATFORM="Windows 10" + before_script: + - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & + - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" + addons: + sauce_connect: true + jwt: + secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + - php: '7.3' env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="16.16299" PLATFORM="Windows 10" before_script: diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index f584324b7..1891fdb35 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -273,6 +273,11 @@ public function execute(WebDriverCommand $command) if ($http_method === 'POST' && $params && is_array($params)) { $encoded_params = json_encode($params); + } elseif ($http_method === 'POST' && $encoded_params === null) { + // Workaround for bug https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943 in Chrome 75. + // Chromedriver now erroneously does not allow POST body to be empty even for the JsonWire protocol. + // If the command POST is empty, here we send some dummy data as a workaround: + $encoded_params = json_encode(['_' => '_']); } curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params); diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 1487689ec..538ae282f 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -15,6 +15,7 @@ namespace Facebook\WebDriver\Remote; +use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Interactions\WebDriverActions; use Facebook\WebDriver\JavaScriptExecutor; use Facebook\WebDriver\WebDriver; @@ -102,6 +103,19 @@ public static function create( $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities); + // Hotfix: W3C WebDriver protocol is not yet supported by php-webdriver, so we must force Chromedriver to + // not use the W3C protocol by default (which is what Chromedriver does starting with version 75). + if ($desired_capabilities->getBrowserName() === WebDriverBrowserType::CHROME) { + $currentChromeOptions = $desired_capabilities->getCapability(ChromeOptions::CAPABILITY); + $chromeOptions = !empty($currentChromeOptions) ? $currentChromeOptions : new ChromeOptions(); + + if (!isset($chromeOptions->toArray()['w3c'])) { + $chromeOptions->setExperimentalOption('w3c', false); + } + + $desired_capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); + } + $executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port); if ($connection_timeout_in_ms !== null) { $executor->setConnectionTimeout($connection_timeout_in_ms); From 550edf5a815694f60654a0a82d0bbe818eeb1514 Mon Sep 17 00:00:00 2001 From: JorisVanEijden Date: Mon, 25 Feb 2019 12:38:04 +0100 Subject: [PATCH 242/600] Do not send null values in cookie array (fixes #626) --- lib/Cookie.php | 50 ++++++++++++++++++++------------------- tests/unit/CookieTest.php | 22 +++++++++++++++++ 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/lib/Cookie.php b/lib/Cookie.php index 57ec7e13a..216ac3033 100644 --- a/lib/Cookie.php +++ b/lib/Cookie.php @@ -27,15 +27,7 @@ class Cookie implements \ArrayAccess { /** @var array */ - protected $cookie = [ - 'name' => null, - 'value' => null, - 'path' => null, - 'domain' => null, - 'expiry' => null, - 'secure' => null, - 'httpOnly' => null, - ]; + protected $cookie = []; /** * @param string $name The name of the cookie; may not be null or an empty string. @@ -51,11 +43,17 @@ public function __construct($name, $value) } /** - * @param array $cookieArray + * @param array $cookieArray The cookie fields; must contain name and value. * @return Cookie */ public static function createFromArray(array $cookieArray) { + if (!isset($cookieArray['name'])) { + throw new InvalidArgumentException('Cookie name should be set'); + } + if (!isset($cookieArray['value'])) { + throw new InvalidArgumentException('Cookie value should be set'); + } $cookie = new self($cookieArray['name'], $cookieArray['value']); if (isset($cookieArray['path'])) { @@ -82,7 +80,7 @@ public static function createFromArray(array $cookieArray) */ public function getName() { - return $this->cookie['name']; + return $this->offsetGet('name'); } /** @@ -90,7 +88,7 @@ public function getName() */ public function getValue() { - return $this->cookie['value']; + return $this->offsetGet('value'); } /** @@ -100,7 +98,7 @@ public function getValue() */ public function setPath($path) { - $this->cookie['path'] = $path; + $this->offsetSet('path', $path); } /** @@ -108,7 +106,7 @@ public function setPath($path) */ public function getPath() { - return $this->cookie['path']; + return $this->offsetGet('path'); } /** @@ -122,7 +120,7 @@ public function setDomain($domain) throw new InvalidArgumentException(sprintf('Cookie domain "%s" should not contain a port', $domain)); } - $this->cookie['domain'] = $domain; + $this->offsetSet('domain', $domain); } /** @@ -130,7 +128,7 @@ public function setDomain($domain) */ public function getDomain() { - return $this->cookie['domain']; + return $this->offsetGet('domain'); } /** @@ -140,7 +138,7 @@ public function getDomain() */ public function setExpiry($expiry) { - $this->cookie['expiry'] = (int) $expiry; + $this->offsetSet('expiry', (int) $expiry); } /** @@ -148,7 +146,7 @@ public function setExpiry($expiry) */ public function getExpiry() { - return $this->cookie['expiry']; + return $this->offsetGet('expiry'); } /** @@ -158,7 +156,7 @@ public function getExpiry() */ public function setSecure($secure) { - $this->cookie['secure'] = $secure; + $this->offsetSet('secure', $secure); } /** @@ -166,7 +164,7 @@ public function setSecure($secure) */ public function isSecure() { - return $this->cookie['secure']; + return $this->offsetGet('secure'); } /** @@ -176,7 +174,7 @@ public function isSecure() */ public function setHttpOnly($httpOnly) { - $this->cookie['httpOnly'] = $httpOnly; + $this->offsetSet('httpOnly', $httpOnly); } /** @@ -184,7 +182,7 @@ public function setHttpOnly($httpOnly) */ public function isHttpOnly() { - return $this->cookie['httpOnly']; + return $this->offsetGet('httpOnly'); } /** @@ -202,12 +200,16 @@ public function offsetExists($offset) public function offsetGet($offset) { - return $this->cookie[$offset]; + return $this->offsetExists($offset) ? $this->cookie[$offset] : null; } public function offsetSet($offset, $value) { - $this->cookie[$offset] = $value; + if ($value === null) { + unset($this->cookie[$offset]); + } else { + $this->cookie[$offset] = $value; + } } public function offsetUnset($offset) diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 3a0679d2c..5fdb43038 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -62,6 +62,28 @@ public function testShouldBeConvertibleToArray(Cookie $cookie) ); } + /** + * Test that there are no null values in the cookie array. + * + * Both JsonWireProtocol and w3c protocol say to leave an entry off + * rather than having a null value. + * + * https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol + * https://w3c.github.io/webdriver/#add-cookie + */ + public function testShouldNotContainNullValues() + { + $cookie = new Cookie('cookieName', 'someValue'); + + $cookie->setHttpOnly(null); + $cookie->setPath(null); + $cookieArray = $cookie->toArray(); + + foreach ($cookieArray as $key => $value) { + $this->assertNotNull($value, $key . ' should not be null'); + } + } + /** * @depends testShouldSetAllProperties * @param Cookie $cookie From d1ad0b14b4f34f3d3eca10c1587b991f612e6746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 10 Jun 2019 13:28:48 +0200 Subject: [PATCH 243/600] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95a4c6c73..e27bd1b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Added - `WebDriverCheckboxes` and `WebDriverRadios` helper classes to simplify interaction with checkboxes and radio buttons. +### Fixed +- Stop sending null values in Cookie object, which is against the protocol and may cause request to remote ends to fail. + +### Changed +- Force Chrome to not use W3C WebDriver protocol. +- Add workaround for Chromedriver bug [2943](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943) which breaks the protocol in Chromedriver 75. + ## 1.6.0 - 2018-05-16 ### Added - Connection and request timeouts could be specified also when creating RemoteWebDriver from existing session ID. From 12ac107aba8af2cc08c549884f5a5844899509e9 Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Mon, 31 Dec 2018 02:23:12 +0200 Subject: [PATCH 244/600] Improved xpath matching related elements to handle input associated to different
    Added @form attribute check, because it's possible to put into a form which is not related to it, see MDN https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form --- lib/AbstractWebDriverCheckboxOrRadio.php | 17 +++++++++++------ tests/functional/WebDriverCheckboxesTest.php | 6 ++++++ tests/functional/WebDriverRadiosTest.php | 6 ++++++ tests/functional/web/form_checkbox_radio.html | 14 +++++++++++++- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/AbstractWebDriverCheckboxOrRadio.php b/lib/AbstractWebDriverCheckboxOrRadio.php index 46288592b..f70a2ef04 100644 --- a/lib/AbstractWebDriverCheckboxOrRadio.php +++ b/lib/AbstractWebDriverCheckboxOrRadio.php @@ -218,12 +218,17 @@ protected function getRelatedElements($value = null) } } - return $this->element->findElements(WebDriverBy::xpath(sprintf( - '//form[@id = %1$s]//input[@name = %2$s%3$s] | //input[@form = %1$s and @name = %2$s%3$s]', - XPathEscaper::escapeQuotes($formId), - XPathEscaper::escapeQuotes($this->name), - $valueSelector - ))); + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form + return $this->element->findElements( + WebDriverBy::xpath(sprintf( + '//form[@id = %1$s]//input[@name = %2$s%3$s' + . ' and ((boolean(@form) = true() and @form = %1$s) or boolean(@form) = false())]' + . ' | //input[@form = %1$s and @name = %2$s%3$s]', + XPathEscaper::escapeQuotes($formId), + XPathEscaper::escapeQuotes($this->name), + $valueSelector + )) + ); } /** diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php index 128d298d5..f7e1407b6 100644 --- a/tests/functional/WebDriverCheckboxesTest.php +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -51,6 +51,12 @@ public function testGetFirstSelectedOption() $this->assertSame('j2a', $c->getFirstSelectedOption()->getAttribute('value')); } + public function testGetFirstSelectedOptionWithSameNameDifferentForm() + { + $radio = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@id="j5b"]'))); + $this->assertEquals('j5b', $radio->getFirstSelectedOption()->getAttribute('value')); + } + public function testSelectByValue() { $selectedOptions = ['j2b', 'j2c']; diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php index 2a1a9869d..369717eb2 100644 --- a/tests/functional/WebDriverRadiosTest.php +++ b/tests/functional/WebDriverRadiosTest.php @@ -55,6 +55,12 @@ public function testGetFirstSelectedOption() $this->assertSame('j3a', $c->getFirstSelectedOption()->getAttribute('value')); } + public function testGetFirstSelectedOptionWithSameNameDifferentForm() + { + $radio = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@id="j4b"]'))); + $this->assertEquals('j4b', $radio->getFirstSelectedOption()->getAttribute('value')); + } + public function testSelectByValue() { $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); diff --git a/tests/functional/web/form_checkbox_radio.html b/tests/functional/web/form_checkbox_radio.html index b51dcfe47..1e13d74e4 100644 --- a/tests/functional/web/form_checkbox_radio.html +++ b/tests/functional/web/form_checkbox_radio.html @@ -27,6 +27,12 @@ + + + + + +
    @@ -36,7 +42,13 @@ -
    + + + + + + +
    From 87f9d0f4dbaf8ecf7c87415cccd3f00ea9e0311c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 10 Jun 2019 13:06:00 +0200 Subject: [PATCH 245/600] Improve readability of tests by structuring theme more in arrange-act-assert way --- tests/functional/WebDriverCheckboxesTest.php | 139 +++++++++++------- tests/functional/WebDriverRadiosTest.php | 73 ++++----- tests/functional/web/form_checkbox_radio.html | 18 ++- 3 files changed, 137 insertions(+), 93 deletions(-) diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php index f7e1407b6..a37fde342 100644 --- a/tests/functional/WebDriverCheckboxesTest.php +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -32,42 +32,55 @@ protected function setUp() public function testIsMultiple() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); - $this->assertTrue($c->isMultiple()); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); + + $this->assertTrue($checkboxes->isMultiple()); } public function testGetOptions() { - $c = new WebDriverCheckboxes( + $checkboxes = new WebDriverCheckboxes( $this->driver->findElement(WebDriverBy::xpath('//form[2]//input[@type="checkbox"]')) ); - $this->assertNotEmpty($c->getOptions()); + + $this->assertNotEmpty($checkboxes->getOptions()); } public function testGetFirstSelectedOption() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); - $c->selectByValue('j2a'); - $this->assertSame('j2a', $c->getFirstSelectedOption()->getAttribute('value')); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); + + $checkboxes->selectByValue('j2a'); + + $this->assertSame('j2a', $checkboxes->getFirstSelectedOption()->getAttribute('value')); } - public function testGetFirstSelectedOptionWithSameNameDifferentForm() + public function testShouldGetFirstSelectedOptionConsideringOnlyElementsAssociatedWithCurrentForm() { - $radio = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@id="j5b"]'))); - $this->assertEquals('j5b', $radio->getFirstSelectedOption()->getAttribute('value')); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@id="j5b"]')) + ); + + $this->assertEquals('j5b', $checkboxes->getFirstSelectedOption()->getAttribute('value')); } public function testSelectByValue() { $selectedOptions = ['j2b', 'j2c']; - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); foreach ($selectedOptions as $index => $selectedOption) { - $c->selectByValue($selectedOption); + $checkboxes->selectByValue($selectedOption); } $selectedValues = []; - foreach ($c->getAllSelectedOptions() as $option) { + foreach ($checkboxes->getAllSelectedOptions() as $option) { $selectedValues[] = $option->getAttribute('value'); } $this->assertSame($selectedOptions, $selectedValues); @@ -75,24 +88,28 @@ public function testSelectByValue() public function testSelectByValueInvalid() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); $this->expectException(NoSuchElementException::class); $this->expectExceptionMessage('Cannot locate checkbox with value: notexist'); - $c->selectByValue('notexist'); + $checkboxes->selectByValue('notexist'); } public function testSelectByIndex() { $selectedOptions = [1 => 'j2b', 2 => 'j2c']; - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); foreach ($selectedOptions as $index => $selectedOption) { - $c->selectByIndex($index); + $checkboxes->selectByIndex($index); } $selectedValues = []; - foreach ($c->getAllSelectedOptions() as $option) { + foreach ($checkboxes->getAllSelectedOptions() as $option) { $selectedValues[] = $option->getAttribute('value'); } $this->assertSame(array_values($selectedOptions), $selectedValues); @@ -100,11 +117,13 @@ public function testSelectByIndex() public function testSelectByIndexInvalid() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); $this->expectException(NoSuchElementException::class); $this->expectExceptionMessage('Cannot locate checkbox with index: ' . PHP_INT_MAX); - $c->selectByIndex(PHP_INT_MAX); + $checkboxes->selectByIndex(PHP_INT_MAX); } /** @@ -115,9 +134,13 @@ public function testSelectByIndexInvalid() */ public function testSelectByVisibleText($text, $value) { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); - $c->selectByVisibleText($text); - $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); + + $checkboxes->selectByVisibleText($text); + + $this->assertSame($value, $checkboxes->getFirstSelectedOption()->getAttribute('value')); } /** @@ -139,9 +162,13 @@ public function selectByVisibleTextDataProvider() */ public function testSelectByVisiblePartialText($text, $value) { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); - $c->selectByVisiblePartialText($text); - $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); + + $checkboxes->selectByVisiblePartialText($text); + + $this->assertSame($value, $checkboxes->getFirstSelectedOption()->getAttribute('value')); } /** @@ -157,51 +184,61 @@ public function selectByVisiblePartialTextDataProvider() public function testDeselectAll() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); - $c->selectByIndex(0); - $this->assertCount(1, $c->getAllSelectedOptions()); - $c->deselectAll(); - $this->assertEmpty($c->getAllSelectedOptions()); + $checkboxes->selectByIndex(0); + $this->assertCount(1, $checkboxes->getAllSelectedOptions()); + $checkboxes->deselectAll(); + $this->assertEmpty($checkboxes->getAllSelectedOptions()); } public function testDeselectByIndex() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); - $c->selectByIndex(0); - $this->assertCount(1, $c->getAllSelectedOptions()); - $c->deselectByIndex(0); - $this->assertEmpty($c->getAllSelectedOptions()); + $checkboxes->selectByIndex(0); + $this->assertCount(1, $checkboxes->getAllSelectedOptions()); + $checkboxes->deselectByIndex(0); + $this->assertEmpty($checkboxes->getAllSelectedOptions()); } public function testDeselectByValue() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); - $c->selectByValue('j2a'); - $this->assertCount(1, $c->getAllSelectedOptions()); - $c->deselectByValue('j2a'); - $this->assertEmpty($c->getAllSelectedOptions()); + $checkboxes->selectByValue('j2a'); + $this->assertCount(1, $checkboxes->getAllSelectedOptions()); + $checkboxes->deselectByValue('j2a'); + $this->assertEmpty($checkboxes->getAllSelectedOptions()); } public function testDeselectByVisibleText() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); - $c->selectByVisibleText('J 2 B'); - $this->assertCount(1, $c->getAllSelectedOptions()); - $c->deselectByVisibleText('J 2 B'); - $this->assertEmpty($c->getAllSelectedOptions()); + $checkboxes->selectByVisibleText('J 2 B'); + $this->assertCount(1, $checkboxes->getAllSelectedOptions()); + $checkboxes->deselectByVisibleText('J 2 B'); + $this->assertEmpty($checkboxes->getAllSelectedOptions()); } public function testDeselectByVisiblePartialText() { - $c = new WebDriverCheckboxes($this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]'))); + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@type="checkbox"]')) + ); - $c->selectByVisiblePartialText('2C'); - $this->assertCount(1, $c->getAllSelectedOptions()); - $c->deselectByVisiblePartialText('2C'); - $this->assertEmpty($c->getAllSelectedOptions()); + $checkboxes->selectByVisiblePartialText('2C'); + $this->assertCount(1, $checkboxes->getAllSelectedOptions()); + $checkboxes->deselectByVisiblePartialText('2C'); + $this->assertEmpty($checkboxes->getAllSelectedOptions()); } } diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php index 369717eb2..2350a401d 100644 --- a/tests/functional/WebDriverRadiosTest.php +++ b/tests/functional/WebDriverRadiosTest.php @@ -33,15 +33,16 @@ protected function setUp() public function testIsMultiple() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); - $this->assertFalse($c->isMultiple()); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $this->assertFalse($radios->isMultiple()); } public function testGetOptions() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $values = []; - foreach ($c->getOptions() as $option) { + foreach ($radios->getOptions() as $option) { $values[] = $option->getAttribute('value'); } @@ -50,53 +51,57 @@ public function testGetOptions() public function testGetFirstSelectedOption() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); - $c->selectByValue('j3a'); - $this->assertSame('j3a', $c->getFirstSelectedOption()->getAttribute('value')); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + + $radios->selectByValue('j3a'); + + $this->assertSame('j3a', $radios->getFirstSelectedOption()->getAttribute('value')); } - public function testGetFirstSelectedOptionWithSameNameDifferentForm() + public function testShouldGetFirstSelectedOptionConsideringOnlyElementsAssociatedWithCurrentForm() { $radio = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@id="j4b"]'))); + $this->assertEquals('j4b', $radio->getFirstSelectedOption()->getAttribute('value')); } public function testSelectByValue() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); - $c->selectByValue('j3b'); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios->selectByValue('j3b'); + + $selectedOptions = $radios->getAllSelectedOptions(); - $selectedOptions = $c->getAllSelectedOptions(); $this->assertCount(1, $selectedOptions); $this->assertSame('j3b', $selectedOptions[0]->getAttribute('value')); } public function testSelectByValueInvalid() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(NoSuchElementException::class); $this->expectExceptionMessage('Cannot locate radio with value: notexist'); - $c->selectByValue('notexist'); + $radios->selectByValue('notexist'); } public function testSelectByIndex() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); - $c->selectByIndex(1); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios->selectByIndex(1); - $allSelectedOptions = $c->getAllSelectedOptions(); + $allSelectedOptions = $radios->getAllSelectedOptions(); $this->assertCount(1, $allSelectedOptions); $this->assertSame('j3b', $allSelectedOptions[0]->getAttribute('value')); } public function testSelectByIndexInvalid() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(NoSuchElementException::class); $this->expectExceptionMessage('Cannot locate radio with index: ' . PHP_INT_MAX); - $c->selectByIndex(PHP_INT_MAX); + $radios->selectByIndex(PHP_INT_MAX); } /** @@ -107,9 +112,9 @@ public function testSelectByIndexInvalid() */ public function testSelectByVisibleText($text, $value) { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); - $c->selectByVisibleText($text); - $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios->selectByVisibleText($text); + $this->assertSame($value, $radios->getFirstSelectedOption()->getAttribute('value')); } /** @@ -131,9 +136,9 @@ public function selectByVisibleTextDataProvider() */ public function testSelectByVisiblePartialText($text, $value) { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); - $c->selectByVisiblePartialText($text); - $this->assertSame($value, $c->getFirstSelectedOption()->getAttribute('value')); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios->selectByVisiblePartialText($text); + $this->assertSame($value, $radios->getFirstSelectedOption()->getAttribute('value')); } /** @@ -149,46 +154,46 @@ public function selectByVisiblePartialTextDataProvider() public function testDeselectAllRadio() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(UnsupportedOperationException::class); $this->expectExceptionMessage('You cannot deselect radio buttons'); - $c->deselectAll(); + $radios->deselectAll(); } public function testDeselectByIndexRadio() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(UnsupportedOperationException::class); $this->expectExceptionMessage('You cannot deselect radio buttons'); - $c->deselectByIndex(0); + $radios->deselectByIndex(0); } public function testDeselectByValueRadio() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(UnsupportedOperationException::class); $this->expectExceptionMessage('You cannot deselect radio buttons'); - $c->deselectByValue('val'); + $radios->deselectByValue('val'); } public function testDeselectByVisibleTextRadio() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(UnsupportedOperationException::class); $this->expectExceptionMessage('You cannot deselect radio buttons'); - $c->deselectByVisibleText('AB'); + $radios->deselectByVisibleText('AB'); } public function testDeselectByVisiblePartialTextRadio() { - $c = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@type="radio"]'))); $this->expectException(UnsupportedOperationException::class); $this->expectExceptionMessage('You cannot deselect radio buttons'); - $c->deselectByVisiblePartialText('AB'); + $radios->deselectByVisiblePartialText('AB'); } } diff --git a/tests/functional/web/form_checkbox_radio.html b/tests/functional/web/form_checkbox_radio.html index 1e13d74e4..3e7c2a19a 100644 --- a/tests/functional/web/form_checkbox_radio.html +++ b/tests/functional/web/form_checkbox_radio.html @@ -5,7 +5,7 @@ Form -
    + @@ -27,28 +27,30 @@ + - + - +
    + - + - + - + - + -
    +
    From e8accbdea92c617e0bfea7bcd5aea522e0c19c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 10 Jun 2019 13:20:45 +0200 Subject: [PATCH 246/600] Extend testcases to cover also form without id --- tests/functional/WebDriverCheckboxesTest.php | 9 +++++++++ tests/functional/WebDriverRadiosTest.php | 13 +++++++++++-- tests/functional/web/form_checkbox_radio.html | 12 ++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php index a37fde342..48b72a53c 100644 --- a/tests/functional/WebDriverCheckboxesTest.php +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -68,6 +68,15 @@ public function testShouldGetFirstSelectedOptionConsideringOnlyElementsAssociate $this->assertEquals('j5b', $checkboxes->getFirstSelectedOption()->getAttribute('value')); } + public function testShouldGetFirstSelectedOptionConsideringOnlyElementsAssociatedWithCurrentFormWithoutId() + { + $checkboxes = new WebDriverCheckboxes( + $this->driver->findElement(WebDriverBy::xpath('//input[@id="j5d"]')) + ); + + $this->assertEquals('j5c', $checkboxes->getFirstSelectedOption()->getAttribute('value')); + } + public function testSelectByValue() { $selectedOptions = ['j2b', 'j2c']; diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php index 2350a401d..4d659772b 100644 --- a/tests/functional/WebDriverRadiosTest.php +++ b/tests/functional/WebDriverRadiosTest.php @@ -60,9 +60,18 @@ public function testGetFirstSelectedOption() public function testShouldGetFirstSelectedOptionConsideringOnlyElementsAssociatedWithCurrentForm() { - $radio = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@id="j4b"]'))); + $radios = new WebDriverRadios($this->driver->findElement(WebDriverBy::xpath('//input[@id="j4b"]'))); - $this->assertEquals('j4b', $radio->getFirstSelectedOption()->getAttribute('value')); + $this->assertEquals('j4b', $radios->getFirstSelectedOption()->getAttribute('value')); + } + + public function testShouldGetFirstSelectedOptionConsideringOnlyElementsAssociatedWithCurrentFormWithoutId() + { + $radios = new WebDriverRadios( + $this->driver->findElement(WebDriverBy::xpath('//input[@id="j4c"]')) + ); + + $this->assertEquals('j4c', $radios->getFirstSelectedOption()->getAttribute('value')); } public function testSelectByValue() diff --git a/tests/functional/web/form_checkbox_radio.html b/tests/functional/web/form_checkbox_radio.html index 3e7c2a19a..fe59896d9 100644 --- a/tests/functional/web/form_checkbox_radio.html +++ b/tests/functional/web/form_checkbox_radio.html @@ -53,5 +53,17 @@
    + + +
    + + + + + + + +
    + From 9a52b1ac036743c31bc127fd7f2f4710e2bc968a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 10 Jun 2019 16:32:25 +0200 Subject: [PATCH 247/600] Release version 1.7.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e27bd1b89..9b5487916 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.7.0 - 2019-06-10 ### Added - `WebDriverCheckboxes` and `WebDriverRadios` helper classes to simplify interaction with checkboxes and radio buttons. From ec7ce5b611e3a73eb789c783760487c89b4999a1 Mon Sep 17 00:00:00 2001 From: Lctrs Date: Tue, 11 Jun 2019 11:47:33 +0200 Subject: [PATCH 248/600] Do not fail if ChromeOptions is already an array DesiredCapabilities::toArray() is a mutable operation which can lead to undesirable side effect of converting ChromeOptions to an array. --- lib/Remote/DesiredCapabilities.php | 1 + lib/Remote/RemoteWebDriver.php | 4 +++- tests/functional/RemoteWebDriverCreateTest.php | 13 +++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 0e1a1ab25..533c8873a 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -156,6 +156,7 @@ public function setJavascriptEnabled($enabled) } /** + * @todo Remove side-effects - not change ie. ChromeOptions::CAPABILITY from instance of ChromeOptions to an array * @return array */ public function toArray() diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 538ae282f..af729f16e 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -109,8 +109,10 @@ public static function create( $currentChromeOptions = $desired_capabilities->getCapability(ChromeOptions::CAPABILITY); $chromeOptions = !empty($currentChromeOptions) ? $currentChromeOptions : new ChromeOptions(); - if (!isset($chromeOptions->toArray()['w3c'])) { + if ($chromeOptions instanceof ChromeOptions && !isset($chromeOptions->toArray()['w3c'])) { $chromeOptions->setExperimentalOption('w3c', false); + } elseif (is_array($chromeOptions) && !isset($chromeOptions['w3c'])) { + $chromeOptions['w3c'] = false; } $desired_capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index f9d7e809e..90c072922 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -49,6 +49,19 @@ public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() $this->assertSame($this->desiredCapabilities->getBrowserName(), $returnedCapabilities->getBrowserName()); } + public function testShouldAcceprCapabilitiesAsAnArray() + { + // Method has a side-effect of converting whole content of desiredCapabilities to an array + $this->desiredCapabilities->toArray(); + + $this->driver = RemoteWebDriver::create( + $this->serverUrl, + $this->desiredCapabilities, + $this->connectionTimeout, + $this->requestTimeout + ); + } + public function testShouldCreateWebDriverWithRequiredCapabilities() { $requiredCapabilities = new DesiredCapabilities(); From f650ee73645a3e95fb0567b25d4f33c13664cbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 12 Jun 2019 11:32:08 +0200 Subject: [PATCH 249/600] Do not send w3c capability as a workaround for browsestack schema validation (fixes #644) --- lib/Remote/RemoteWebDriver.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index af729f16e..71f45704e 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -105,7 +105,9 @@ public static function create( // Hotfix: W3C WebDriver protocol is not yet supported by php-webdriver, so we must force Chromedriver to // not use the W3C protocol by default (which is what Chromedriver does starting with version 75). - if ($desired_capabilities->getBrowserName() === WebDriverBrowserType::CHROME) { + if ($desired_capabilities->getBrowserName() === WebDriverBrowserType::CHROME + && mb_strpos($selenium_server_url, 'browserstack') === false // see https://github.com/facebook/php-webdriver/issues/644 + ) { $currentChromeOptions = $desired_capabilities->getCapability(ChromeOptions::CAPABILITY); $chromeOptions = !empty($currentChromeOptions) ? $currentChromeOptions : new ChromeOptions(); From e43de70f3c7166169d0f14a374505392734160e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 13 Jun 2019 10:02:18 +0200 Subject: [PATCH 250/600] Release version 1.7.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b5487916..a5e4ca748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +## 1.7.1 - 2019-06-13 +### Fixed +- Error `Call to a member function toArray()` if capabilities were already converted to an array. +- Temporarily do not send capabilities to disable W3C WebDriver protocol when BrowserStack hub is used. + ## 1.7.0 - 2019-06-10 ### Added - `WebDriverCheckboxes` and `WebDriverRadios` helper classes to simplify interaction with checkboxes and radio buttons. From 3f73de8364e7285115750e7e47b9a27e08c730d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Jun 2019 11:33:44 +0200 Subject: [PATCH 251/600] Revert Chromedriver bug workaround, which is fixed in Chromedriver 75.0.3770.90 --- .travis.yml | 2 +- CHANGELOG.md | 3 +++ lib/Remote/HttpCommandExecutor.php | 5 ----- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index b6850baf1..ac6cc1e24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,7 +47,7 @@ matrix: # Stable Chrome + Chromedriver 75+ inside Travis environment - php: '7.3' - env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" CHROMEDRIVER_VERSION="75.0.3770.8" + env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" CHROMEDRIVER_VERSION="75.0.3770.90" addons: chrome: stable diff --git a/CHANGELOG.md b/CHANGELOG.md index a5e4ca748..f1e733516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Changed +- Revert no longer needed workaround for Chromedriver bug [2943](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943). + ## 1.7.1 - 2019-06-13 ### Fixed - Error `Call to a member function toArray()` if capabilities were already converted to an array. diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 1891fdb35..f584324b7 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -273,11 +273,6 @@ public function execute(WebDriverCommand $command) if ($http_method === 'POST' && $params && is_array($params)) { $encoded_params = json_encode($params); - } elseif ($http_method === 'POST' && $encoded_params === null) { - // Workaround for bug https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943 in Chrome 75. - // Chromedriver now erroneously does not allow POST body to be empty even for the JsonWire protocol. - // If the command POST is empty, here we send some dummy data as a workaround: - $encoded_params = json_encode(['_' => '_']); } curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params); From 4f8b32289daa41c9c96b6a9dbfcb352a24e5af1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 1 Nov 2019 19:16:13 +0000 Subject: [PATCH 252/600] Download latest chromedriver without a need of manual version bumping --- .travis.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index ac6cc1e24..37dfc2cf1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,15 +39,9 @@ matrix: addons: firefox: "45.8.0esr" - # Stable Chrome + Chromedriver 74 inside Travis environment + # Stable Chrome + Chromedriver inside Travis environment - php: '7.3' - env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" CHROMEDRIVER_VERSION="74.0.3729.6" - addons: - chrome: stable - - # Stable Chrome + Chromedriver 75+ inside Travis environment - - php: '7.3' - env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" CHROMEDRIVER_VERSION="75.0.3770.90" + env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" addons: chrome: stable @@ -102,7 +96,7 @@ install: - travis_retry composer update --no-interaction $DEPENDENCIES before_script: - - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi + - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; CHROMEDRIVER_VERSION=$(wget -qO- "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"); wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.8.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; fi From 87be63361d6670b8110b7d084887746b1adc685b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 9 Apr 2018 16:25:57 +0200 Subject: [PATCH 253/600] W3C-compatible implementation --- .travis.yml | 12 +- CONTRIBUTING.md | 10 +- lib/AbstractWebDriverCheckboxOrRadio.php | 2 +- lib/Cookie.php | 8 +- lib/Exception/WebDriverException.php | 50 ++++- lib/Interactions/WebDriverActions.php | 1 - lib/Remote/DriverCommand.php | 4 + lib/Remote/HttpCommandExecutor.php | 63 ++++++- lib/Remote/JsonWireCompat.php | 102 ++++++++++ lib/Remote/RemoteMouse.php | 174 +++++++++++++++++- lib/Remote/RemoteTargetLocator.php | 4 +- lib/Remote/RemoteWebDriver.php | 82 ++++++--- lib/Remote/RemoteWebElement.php | 112 ++++++++--- lib/WebDriverDimension.php | 12 +- lib/WebDriverOptions.php | 9 +- lib/WebDriverPoint.php | 4 +- lib/WebDriverTimeouts.php | 34 +++- .../functional/RemoteWebDriverCreateTest.php | 5 +- .../RemoteWebDriverFindElementTest.php | 20 ++ tests/functional/RemoteWebDriverTest.php | 23 ++- tests/functional/RemoteWebElementTest.php | 4 + tests/functional/WebDriverActionsTest.php | 24 ++- tests/functional/WebDriverTestCase.php | 7 +- tests/functional/web/escape_css.html | 14 ++ tests/functional/web/upload.html | 2 +- 25 files changed, 699 insertions(+), 83 deletions(-) create mode 100644 lib/Remote/JsonWireCompat.php create mode 100644 tests/functional/web/escape_css.html diff --git a/.travis.yml b/.travis.yml index 37dfc2cf1..47ddb461e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,11 +34,21 @@ matrix: env: DEPENDENCIES="--prefer-lowest" # Firefox inside Travis environment - - php: '7.3' + - name: 'Firefox 45 on Travis (OSS protocol)' + php: '7.3' env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" + # Firefox with Geckodriver (W3C mode) inside Travis environment + - name: 'Firefox latest on Travis (W3C protocol)' + php: 7.3 + env: + - BROWSER_NAME="firefox" + - GECKODRIVER="1" + addons: + firefox: latest + # Stable Chrome + Chromedriver inside Travis environment - php: '7.3' env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a01c7adb..741a140a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,10 +37,10 @@ For the functional tests you must first [download](http://selenium-release.stora the selenium standalone server, start the local PHP server which will serve the test pages and then run the `functional` test suite: - java -jar selenium-server-standalone-2.53.1.jar -log selenium.log & + java -jar selenium-server-standalone-3.9.1.jar -log selenium.log & php -S localhost:8000 -t tests/functional/web/ & ./vendor/bin/phpunit --testsuite functional - + The functional tests will be started in HtmlUnit headless browser by default. If you want to run them in eg. Firefox, simply set the `BROWSER_NAME` environment variable: @@ -48,6 +48,12 @@ simply set the `BROWSER_NAME` environment variable: export BROWSER_NAME="firefox" ./vendor/bin/phpunit --testsuite functional +To test with Geckodriver, [download](https://github.com/mozilla/geckodriver/releases) and start the server, then run: + + export GECKODRIVER=1 + export BROWSER_NAME=firefox + ./vendor/bin/phpunit --testsuite functional + ### Check coding style Your code-style should comply with [PSR-2](http://www.php-fig.org/psr/psr-2/). To make sure your code matches this requirement run: diff --git a/lib/AbstractWebDriverCheckboxOrRadio.php b/lib/AbstractWebDriverCheckboxOrRadio.php index f70a2ef04..1268ce7c0 100644 --- a/lib/AbstractWebDriverCheckboxOrRadio.php +++ b/lib/AbstractWebDriverCheckboxOrRadio.php @@ -211,7 +211,7 @@ protected function getRelatedElements($value = null) $form = $this->element->findElement(WebDriverBy::xpath('ancestor::form')); $formId = $form->getAttribute('id'); - if ($formId === '') { + if (!$formId) { return $form->findElements(WebDriverBy::xpath( sprintf('.//input[@name = %s%s]', XPathEscaper::escapeQuotes($this->name), $valueSelector) )); diff --git a/lib/Cookie.php b/lib/Cookie.php index 216ac3033..170b46486 100644 --- a/lib/Cookie.php +++ b/lib/Cookie.php @@ -190,7 +190,13 @@ public function isHttpOnly() */ public function toArray() { - return $this->cookie; + $cookie = $this->cookie; + if (!isset($cookie['secure'])) { + // Passing a boolean value for the "secure" flag is mandatory when using geckodriver + $cookie['secure'] = false; + } + + return $cookie; } public function offsetExists($offset) diff --git a/lib/Exception/WebDriverException.php b/lib/Exception/WebDriverException.php index 8545729ad..b17b2f70f 100644 --- a/lib/Exception/WebDriverException.php +++ b/lib/Exception/WebDriverException.php @@ -42,7 +42,7 @@ public function getResults() /** * Throw WebDriverExceptions based on WebDriver status code. * - * @param int $status_code + * @param int|string $status_code * @param string $message * @param mixed $results * @@ -85,6 +85,54 @@ public function getResults() */ public static function throwException($status_code, $message, $results) { + if (is_string($status_code)) { + // see https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors + switch ($status_code) { + case 'no such element': + throw new NoSuchElementException($message, $results); + case 'no such frame': + throw new NoSuchFrameException($message, $results); + case 'unknown command': + throw new UnknownCommandException($message, $results); + case 'stale element reference': + throw new StaleElementReferenceException($message, $results); + case 'invalid element state': + throw new InvalidElementStateException($message, $results); + case 'unknown error': + throw new UnknownServerException($message, $results); + case 'unsupported operation': + throw new ExpectedException($message, $results); + case 'element not interactable': + throw new ElementNotSelectableException($message, $results); + case 'no such window': + throw new NoSuchDocumentException($message, $results); + case 'javascript error': + throw new UnexpectedJavascriptException($message, $results); + case 'timeout': + throw new TimeOutException($message, $results); + case 'no such window': + throw new NoSuchWindowException($message, $results); + case 'invalid cookie domain': + throw new InvalidCookieDomainException($message, $results); + case 'unable to set cookie': + throw new UnableToSetCookieException($message, $results); + case 'unexpected alert open': + throw new UnexpectedAlertOpenException($message, $results); + case 'no such alert': + throw new NoAlertOpenException($message, $results); + case 'script timeout': + throw new ScriptTimeoutException($message, $results); + case 'invalid selector': + throw new InvalidSelectorException($message, $results); + case 'session not created': + throw new SessionNotCreatedException($message, $results); + case 'move target out of bounds': + throw new MoveTargetOutOfBoundsException($message, $results); + default: + throw new UnrecognizedExceptionException($message, $results); + } + } + switch ($status_code) { case 1: throw new IndexOutOfBoundsException($message, $results); diff --git a/lib/Interactions/WebDriverActions.php b/lib/Interactions/WebDriverActions.php index e97796854..66ac7c1ab 100644 --- a/lib/Interactions/WebDriverActions.php +++ b/lib/Interactions/WebDriverActions.php @@ -25,7 +25,6 @@ use Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction; use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction; use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction; -use Facebook\WebDriver\WebDriver; use Facebook\WebDriver\WebDriverElement; use Facebook\WebDriver\WebDriverHasInputDevices; diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index c69052030..fd24a691c 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -146,6 +146,10 @@ class DriverCommand const GET_NETWORK_CONNECTION = 'getNetworkConnection'; const SET_NETWORK_CONNECTION = 'setNetworkConnection'; + // W3C specific + const ACTIONS = 'actions'; + const GET_ELEMENT_PROPERTY = 'getElementProperty'; + private function __construct() { } diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index f584324b7..c783b2892 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -137,6 +137,29 @@ class HttpCommandExecutor implements WebDriverCommandExecutor DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'], DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'], ]; + /** + * @var array Will be merged with $commands + */ + protected static $w3cCompliantCommands = [ + DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/accept'], + DriverCommand::ACTIONS => ['method' => 'POST', 'url' => '/session/:sessionId/actions'], + DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/dismiss'], + DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'], + DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/async'], + DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window'], + DriverCommand::GET_ELEMENT_LOCATION => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], + DriverCommand::GET_ELEMENT_PROPERTY => [ + 'method' => 'GET', + 'url' => '/session/:sessionId/element/:id/property/:name', + ], + DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], + DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window/handles'], + DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'], + DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], + DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert/text'], + DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], + DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], + ]; /** * @var string */ @@ -145,6 +168,10 @@ class HttpCommandExecutor implements WebDriverCommandExecutor * @var resource */ protected $curl; + /** + * @var bool + */ + protected $w3cCompliant = true; /** * @param string $url @@ -153,6 +180,8 @@ class HttpCommandExecutor implements WebDriverCommandExecutor */ public function __construct($url, $http_proxy = null, $http_proxy_port = null) { + self::$w3cCompliantCommands = array_merge(self::$commands, self::$w3cCompliantCommands); + $this->url = $url; $this->curl = curl_init(); @@ -179,6 +208,11 @@ public function __construct($url, $http_proxy = null, $http_proxy_port = null) $this->setConnectionTimeout(30000); } + public function disableW3CCompliance() + { + $this->w3cCompliant = false; + } + /** * Set timeout for the connect phase * @@ -226,11 +260,19 @@ public function setRequestTimeout($timeout_in_ms) */ public function execute(WebDriverCommand $command) { - if (!isset(self::$commands[$command->getName()])) { - throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); + $commandName = $command->getName(); + if (!isset(self::$commands[$commandName])) { + if ($this->w3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) { + throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); + } + } + + if ($this->w3cCompliant) { + $raw = self::$w3cCompliantCommands[$command->getName()]; + } else { + $raw = self::$commands[$command->getName()]; } - $raw = self::$commands[$command->getName()]; $http_method = $raw['method']; $url = $raw['url']; $url = str_replace(':sessionId', $command->getSessionID(), $url); @@ -317,12 +359,23 @@ public function execute(WebDriverCommand $command) } $sessionId = null; - if (is_array($results) && array_key_exists('sessionId', $results)) { + if (is_array($value) && array_key_exists('sessionId', $value)) { + // W3C's WebDriver + $sessionId = $value['sessionId']; + } elseif (is_array($results) && array_key_exists('sessionId', $results)) { + // Legacy JsonWire $sessionId = $results['sessionId']; } + // @see https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors + if (isset($value['error'])) { + // W3C's WebDriver + WebDriverException::throwException($value['error'], $message, $results); + } + $status = isset($results['status']) ? $results['status'] : 0; - if ($status != 0) { + if ($status !== 0) { + // Legacy JsonWire WebDriverException::throwException($status, $message, $results); } diff --git a/lib/Remote/JsonWireCompat.php b/lib/Remote/JsonWireCompat.php new file mode 100644 index 000000000..78b9cba0e --- /dev/null +++ b/lib/Remote/JsonWireCompat.php @@ -0,0 +1,102 @@ +getMechanism(); + $value = $by->getValue(); + + if ($w3cCompliant) { + switch ($mechanism) { + // Convert to CSS selectors + case 'class name': + $mechanism = 'css selector'; + $value = sprintf('.%s', self::escapeSelector($value)); + break; + case 'id': + $mechanism = 'css selector'; + $value = sprintf('#%s', self::escapeSelector($value)); + break; + case 'name': + $mechanism = 'css selector'; + $value = sprintf('[name=\'%s\']', self::escapeSelector($value)); + break; + } + } + + return ['using' => $mechanism, 'value' => $value]; + } + + /** + * Escapes a CSS selector. + * + * Code adapted from the Zend Escaper project. + * + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @see https://github.com/zendframework/zend-escaper/blob/master/src/Escaper.php + * + * @param string $selector + * @return string + */ + private static function escapeSelector($selector) + { + return preg_replace_callback('/[^a-z0-9]/iSu', function ($matches) { + $chr = $matches[0]; + if (mb_strlen($chr) == 1) { + $ord = ord($chr); + } else { + $chr = mb_convert_encoding($chr, 'UTF-32BE', 'UTF-8'); + $ord = hexdec(bin2hex($chr)); + } + + return sprintf('\\%X ', $ord); + }, $selector); + } +} diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index 48c578df7..aa0d59829 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -27,13 +27,19 @@ class RemoteMouse implements WebDriverMouse * @var RemoteExecuteMethod */ private $executor; + /** + * @var bool + */ + private $w3cCompliant; /** * @param RemoteExecuteMethod $executor + * @param bool $w3cCompliant */ - public function __construct(RemoteExecuteMethod $executor) + public function __construct(RemoteExecuteMethod $executor, $w3cCompliant = false) { $this->executor = $executor; + $this->w3cCompliant = $w3cCompliant; } /** @@ -43,6 +49,22 @@ public function __construct(RemoteExecuteMethod $executor) */ public function click(WebDriverCoordinates $where = null) { + if ($this->w3cCompliant) { + $moveAction = $where ? [$this->createMoveAction($where)] : []; + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [ + [ + 'type' => 'pointer', + 'id' => 'mouse', + 'parameters' => ['pointerType' => 'mouse'], + 'actions' => array_merge($moveAction, $this->createClickActions()), + ], + ], + ]); + + return $this; + } + $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::CLICK, [ 'button' => 0, @@ -58,6 +80,33 @@ public function click(WebDriverCoordinates $where = null) */ public function contextClick(WebDriverCoordinates $where = null) { + if ($this->w3cCompliant) { + $moveAction = $where ? [$this->createMoveAction($where)] : []; + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [ + [ + 'type' => 'pointer', + 'id' => 'mouse', + 'parameters' => ['pointerType' => 'mouse'], + 'actions' => array_merge($moveAction, [ + [ + 'type' => 'pointerDown', + 'duration' => 0, + 'button' => 2, + ], + [ + 'type' => 'pointerUp', + 'duration' => 0, + 'button' => 2, + ], + ]), + ], + ], + ]); + + return $this; + } + $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::CLICK, [ 'button' => 2, @@ -73,6 +122,23 @@ public function contextClick(WebDriverCoordinates $where = null) */ public function doubleClick(WebDriverCoordinates $where = null) { + if ($this->w3cCompliant) { + $clickActions = $this->createClickActions(); + $moveAction = null === $where ? [] : [$this->createMoveAction($where)]; + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [ + [ + 'type' => 'pointer', + 'id' => 'mouse', + 'parameters' => ['pointerType' => 'mouse'], + 'actions' => array_merge($moveAction, $clickActions, $clickActions), + ], + ], + ]); + + return $this; + } + $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::DOUBLE_CLICK); @@ -86,6 +152,28 @@ public function doubleClick(WebDriverCoordinates $where = null) */ public function mouseDown(WebDriverCoordinates $where = null) { + if ($this->w3cCompliant) { + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [ + [ + 'type' => 'pointer', + 'id' => 'mouse', + 'parameters' => ['pointerType' => 'mouse'], + 'actions' => [ + $this->createMoveAction($where), + [ + 'type' => 'pointerDown', + 'duration' => 0, + 'button' => 0, + ], + ], + ], + ], + ]); + + return $this; + } + $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::MOUSE_DOWN); @@ -104,6 +192,21 @@ public function mouseMove( $x_offset = null, $y_offset = null ) { + if ($this->w3cCompliant) { + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [ + [ + 'type' => 'pointer', + 'id' => 'mouse', + 'parameters' => ['pointerType' => 'mouse'], + 'actions' => [$this->createMoveAction($where, $x_offset, $y_offset)], + ], + ], + ]); + + return $this; + } + $params = []; if ($where !== null) { $params['element'] = $where->getAuxiliary(); @@ -114,6 +217,7 @@ public function mouseMove( if ($y_offset !== null) { $params['yoffset'] = $y_offset; } + $this->executor->execute(DriverCommand::MOVE_TO, $params); return $this; @@ -126,6 +230,29 @@ public function mouseMove( */ public function mouseUp(WebDriverCoordinates $where = null) { + if ($this->w3cCompliant) { + $moveAction = $where ? [$this->createMoveAction($where)] : []; + + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [ + [ + 'type' => 'pointer', + 'id' => 'mouse', + 'parameters' => ['pointerType' => 'mouse'], + 'actions' => array_merge($moveAction, [ + [ + 'type' => 'pointerDown', + 'duration' => 0, + 'button' => 0, + ], + ]), + ], + ], + ]); + + return $this; + } + $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::MOUSE_UP); @@ -141,4 +268,49 @@ protected function moveIfNeeded(WebDriverCoordinates $where = null) $this->mouseMove($where); } } + + /** + * @param WebDriverCoordinates $where + * @param int|null $x_offset + * @param int|null $y_offset + * + * @return array + */ + private function createMoveAction( + WebDriverCoordinates $where = null, + $x_offset = null, + $y_offset = null + ) { + $move_action = [ + 'type' => 'pointerMove', + 'duration' => 0, + 'x' => $x_offset === null ? 0 : $x_offset, + 'y' => $y_offset === null ? 0 : $y_offset, + ]; + + if ($where !== null) { + $move_action['origin'] = [JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $where->getAuxiliary()]; + } + + return $move_action; + } + + /** + * @return array + */ + private function createClickActions() + { + return [ + [ + 'type' => 'pointerDown', + 'duration' => 0, + 'button' => 0, + ], + [ + 'type' => 'pointerUp', + 'duration' => 0, + 'button' => 0, + ], + ]; + } } diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 5c218075d..55a879c0d 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -112,6 +112,8 @@ public function activeElement() $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []); $method = new RemoteExecuteMethod($this->driver); - return new RemoteWebElement($method, $response['ELEMENT']); + $w3cCompliant = $this->driver instanceof RemoteWebDriver ? $this->driver->isW3cCompliant() : false; + + return new RemoteWebElement($method, JsonWireCompat::getElement($response), $w3cCompliant); } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 71f45704e..6d3a7d833 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -59,19 +59,26 @@ class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInpu * @var RemoteExecuteMethod */ protected $executeMethod; + /** + * @var bool + */ + protected $w3cCompliant; /** * @param HttpCommandExecutor $commandExecutor * @param string $sessionId * @param WebDriverCapabilities|null $capabilities + * @param bool $w3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec */ protected function __construct( HttpCommandExecutor $commandExecutor, $sessionId, - WebDriverCapabilities $capabilities = null + WebDriverCapabilities $capabilities = null, + $w3cCompliant = false ) { $this->executor = $commandExecutor; $this->sessionID = $sessionId; + $this->w3cCompliant = $w3cCompliant; if ($capabilities !== null) { $this->capabilities = $capabilities; @@ -88,6 +95,7 @@ protected function __construct( * @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through * @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through * @param DesiredCapabilities $required_capabilities The required capabilities + * * @return static */ public static function create( @@ -99,6 +107,7 @@ public static function create( $http_proxy_port = null, DesiredCapabilities $required_capabilities = null ) { + // BC layer to not break the method signature $selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url); $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities); @@ -128,23 +137,43 @@ public static function create( $executor->setRequestTimeout($request_timeout_in_ms); } + // W3C + $parameters = [ + 'capabilities' => [ + 'firstMatch' => [$desired_capabilities->toArray()], + ], + ]; + + // Legacy protocol + if (null !== $required_capabilities && $required_capabilities_array = $required_capabilities->toArray()) { + $parameters['capabilities']['alwaysMatch'] = $required_capabilities_array; + } + if ($required_capabilities !== null) { // TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities. - // This will probably change in future with the W3C WebDriver spec, but is the only way how to pass these - // values now. + // This has changed with the W3C WebDriver spec, but is the only way how to pass these + // values with the legacy protocol. $desired_capabilities->setCapability('requiredCapabilities', $required_capabilities->toArray()); } + $parameters['desiredCapabilities'] = $desired_capabilities->toArray(); + $command = new WebDriverCommand( null, DriverCommand::NEW_SESSION, - ['desiredCapabilities' => $desired_capabilities->toArray()] + $parameters ); $response = $executor->execute($command); - $returnedCapabilities = new DesiredCapabilities($response->getValue()); + $value = $response->getValue(); + + if (!$w3c_compliant = isset($value['capabilities'])) { + $executor->disableW3CCompliance(); + } - $driver = new static($executor, $response->getSessionID(), $returnedCapabilities); + $returnedCapabilities = new DesiredCapabilities($w3c_compliant ? $value['capabilities'] : $value); + + $driver = new static($executor, $response->getSessionID(), $returnedCapabilities, $w3c_compliant); return $driver; } @@ -167,7 +196,9 @@ public static function createBySessionID( $connection_timeout_in_ms = null, $request_timeout_in_ms = null ) { - $executor = new HttpCommandExecutor($selenium_server_url); + // BC layer to not break the method signature + $w3c_compliant = func_num_args() > 3 ? func_get_arg(3) : false; + $executor = new HttpCommandExecutor($selenium_server_url, null, null); if ($connection_timeout_in_ms !== null) { $executor->setConnectionTimeout($connection_timeout_in_ms); } @@ -175,7 +206,7 @@ public static function createBySessionID( $executor->setRequestTimeout($request_timeout_in_ms); } - return new static($executor, $session_id); + return new static($executor, $session_id, null, $w3c_compliant); } /** @@ -199,13 +230,12 @@ public function close() */ public function findElement(WebDriverBy $by) { - $params = ['using' => $by->getMechanism(), 'value' => $by->getValue()]; $raw_element = $this->execute( DriverCommand::FIND_ELEMENT, - $params + JsonWireCompat::getUsing($by, $this->w3cCompliant) ); - return $this->newElement($raw_element['ELEMENT']); + return $this->newElement(JsonWireCompat::getElement($raw_element)); } /** @@ -217,15 +247,14 @@ public function findElement(WebDriverBy $by) */ public function findElements(WebDriverBy $by) { - $params = ['using' => $by->getMechanism(), 'value' => $by->getValue()]; $raw_elements = $this->execute( DriverCommand::FIND_ELEMENTS, - $params + JsonWireCompat::getUsing($by, $this->w3cCompliant) ); $elements = []; foreach ($raw_elements as $raw_element) { - $elements[] = $this->newElement($raw_element['ELEMENT']); + $elements[] = $this->newElement(JsonWireCompat::getElement($raw_element)); } return $elements; @@ -399,7 +428,7 @@ public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) */ public function manage() { - return new WebDriverOptions($this->getExecuteMethod()); + return new WebDriverOptions($this->getExecuteMethod(), $this->w3cCompliant); } /** @@ -430,7 +459,7 @@ public function switchTo() public function getMouse() { if (!$this->mouse) { - $this->mouse = new RemoteMouse($this->getExecuteMethod()); + $this->mouse = new RemoteMouse($this->getExecuteMethod(), $this->w3cCompliant); } return $this->mouse; @@ -541,7 +570,7 @@ public function getCapabilities() */ public static function getAllSessions($selenium_server_url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000) { - $executor = new HttpCommandExecutor($selenium_server_url); + $executor = new HttpCommandExecutor($selenium_server_url, null, null); $executor->setConnectionTimeout($timeout_in_ms); $command = new WebDriverCommand( @@ -570,6 +599,15 @@ public function execute($command_name, $params = []) return null; } + /** + * @internal + * @return bool + */ + public function isW3cCompliant() + { + return $this->w3cCompliant; + } + /** * Prepare arguments for JavaScript injection * @@ -581,9 +619,11 @@ protected function prepareScriptArguments(array $arguments) $args = []; foreach ($arguments as $key => $value) { if ($value instanceof WebDriverElement) { - $args[$key] = ['ELEMENT' => $value->getID()]; + $args[$key] = [ + $this->w3cCompliant ? JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER : 'ELEMENT' => $value->getID(), + ]; } else { - if (is_array($value)) { + if (\is_array($value)) { $value = $this->prepareScriptArguments($value); } $args[$key] = $value; @@ -613,7 +653,7 @@ protected function getExecuteMethod() */ protected function newElement($id) { - return new RemoteWebElement($this->getExecuteMethod(), $id); + return new RemoteWebElement($this->getExecuteMethod(), $id, $this->w3cCompliant); } /** @@ -629,7 +669,7 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities return new DesiredCapabilities(); } - if (is_array($desired_capabilities)) { + if (\is_array($desired_capabilities)) { return new DesiredCapabilities($desired_capabilities); } diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 26936d8b9..b07b18227 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -15,6 +15,7 @@ namespace Facebook\WebDriver\Remote; +use Facebook\WebDriver\Exception\UnsupportedOperationException; use Facebook\WebDriver\Exception\WebDriverException; use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates; use Facebook\WebDriver\Internal\WebDriverLocatable; @@ -42,16 +43,22 @@ class RemoteWebElement implements WebDriverElement, WebDriverLocatable * @var UselessFileDetector */ protected $fileDetector; + /** + * @var bool + */ + protected $w3cCompliant; /** * @param RemoteExecuteMethod $executor * @param string $id + * @param bool $w3cCompliant */ - public function __construct(RemoteExecuteMethod $executor, $id) + public function __construct(RemoteExecuteMethod $executor, $id, $w3cCompliant = false) { $this->executor = $executor; $this->id = $id; $this->fileDetector = new UselessFileDetector(); + $this->w3cCompliant = $w3cCompliant; } /** @@ -66,6 +73,23 @@ public function clear() [':id' => $this->id] ); + if ($this->w3cCompliant) { + $this->executor->execute(DriverCommand::ACTIONS, [ + 'actions' => [[ + 'type' => 'key', + 'id' => 'keyboard', + 'actions' => [ + ['type' => 'keyDown' , 'value' => WebDriverKeys::CONTROL], + ['type' => 'keyDown' , 'value' => 'a'], + ['type' => 'keyUp' , 'value' => WebDriverKeys::CONTROL], + ['type' => 'keyUp' , 'value' => 'a'], + ['type' => 'keyDown' , 'value' => WebDriverKeys::BACKSPACE], + ['type' => 'keyUp' , 'value' => WebDriverKeys::BACKSPACE], + ], + ]], + ]); + } + return $this; } @@ -94,17 +118,15 @@ public function click() */ public function findElement(WebDriverBy $by) { - $params = [ - 'using' => $by->getMechanism(), - 'value' => $by->getValue(), - ':id' => $this->id, - ]; + $params = JsonWireCompat::getUsing($by, $this->w3cCompliant); + $params[':id'] = $this->id; + $raw_element = $this->executor->execute( DriverCommand::FIND_CHILD_ELEMENT, $params ); - return $this->newElement($raw_element['ELEMENT']); + return $this->newElement(JsonWireCompat::getElement($raw_element)); } /** @@ -117,11 +139,8 @@ public function findElement(WebDriverBy $by) */ public function findElements(WebDriverBy $by) { - $params = [ - 'using' => $by->getMechanism(), - 'value' => $by->getValue(), - ':id' => $this->id, - ]; + $params = JsonWireCompat::getUsing($by, $this->w3cCompliant); + $params[':id'] = $this->id; $raw_elements = $this->executor->execute( DriverCommand::FIND_CHILD_ELEMENTS, $params @@ -129,7 +148,7 @@ public function findElements(WebDriverBy $by) $elements = []; foreach ($raw_elements as $raw_element) { - $elements[] = $this->newElement($raw_element['ELEMENT']); + $elements[] = $this->newElement(JsonWireCompat::getElement($raw_element)); } return $elements; @@ -148,10 +167,23 @@ public function getAttribute($attribute_name) ':id' => $this->id, ]; - return $this->executor->execute( - DriverCommand::GET_ELEMENT_ATTRIBUTE, - $params - ); + if ($this->w3cCompliant && ($attribute_name === 'value' || $attribute_name === 'index')) { + $value = $this->executor->execute(DriverCommand::GET_ELEMENT_PROPERTY, $params); + + if ($value === true) { + return 'true'; + } + + if ($value === false) { + return 'false'; + } + + if ($value !== null) { + return (string) $value; + } + } + + return $this->executor->execute(DriverCommand::GET_ELEMENT_ATTRIBUTE, $params); } /** @@ -325,20 +357,37 @@ public function sendKeys($value) { $local_file = $this->fileDetector->getLocalFile($value); if ($local_file === null) { + if ($this->w3cCompliant) { + $params = [ + 'text' => (string) $value, + ':id' => $this->id, + ]; + } else { + $params = [ + 'value' => WebDriverKeys::encode($value), + ':id' => $this->id, + ]; + } + + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); + + return $this; + } + + if ($this->w3cCompliant) { $params = [ - 'value' => WebDriverKeys::encode($value), + 'text' => $local_file, ':id' => $this->id, ]; - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); } else { - $remote_path = $this->upload($local_file); $params = [ - 'value' => WebDriverKeys::encode($remote_path), + 'value' => WebDriverKeys::encode($this->upload($local_file)), ':id' => $this->id, ]; - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); } + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); + return $this; } @@ -371,6 +420,19 @@ public function setFileDetector(FileDetector $detector) */ public function submit() { + if ($this->w3cCompliant) { + $this->executor->execute(DriverCommand::EXECUTE_SCRIPT, [ + // cannot call the submit method directly in case an input of this form is named "submit" + 'script' => sprintf( + 'return Object.getPrototypeOf(%1$s).submit.call(%1$s);', + 'form' === $this->getTagName() ? 'arguments[0]' : 'arguments[0].form' + ), + 'args' => [[JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $this->id]], + ]); + + return $this; + } + $this->executor->execute( DriverCommand::SUBMIT_ELEMENT, [':id' => $this->id] @@ -397,6 +459,10 @@ public function getID() */ public function equals(WebDriverElement $other) { + if ($this->w3cCompliant) { + throw new UnsupportedOperationException('"elementEquals" is not supported by the W3C specification'); + } + return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, [ ':id' => $this->id, ':other' => $other->getID(), @@ -412,7 +478,7 @@ public function equals(WebDriverElement $other) */ protected function newElement($id) { - return new static($this->executor, $id); + return new static($this->executor, $id, $this->w3cCompliant); } /** diff --git a/lib/WebDriverDimension.php b/lib/WebDriverDimension.php index 308c1990f..81a223989 100644 --- a/lib/WebDriverDimension.php +++ b/lib/WebDriverDimension.php @@ -21,17 +21,17 @@ class WebDriverDimension { /** - * @var int + * @var int|float */ private $height; /** - * @var int + * @var int|float */ private $width; /** - * @param int $width - * @param int $height + * @param int|float $width + * @param int|float $height */ public function __construct($width, $height) { @@ -46,7 +46,7 @@ public function __construct($width, $height) */ public function getHeight() { - return $this->height; + return (int) $this->height; } /** @@ -56,7 +56,7 @@ public function getHeight() */ public function getWidth() { - return $this->width; + return (int) $this->width; } /** diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index bec7fd18b..4c584bd07 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -28,10 +28,15 @@ class WebDriverOptions * @var ExecuteMethod */ protected $executor; + /** + * @var bool + */ + protected $w3cCompliant; - public function __construct(ExecuteMethod $executor) + public function __construct(ExecuteMethod $executor, $w3cCompliant = false) { $this->executor = $executor; + $this->w3cCompliant = $w3cCompliant; } /** @@ -128,7 +133,7 @@ public function getCookies() */ public function timeouts() { - return new WebDriverTimeouts($this->executor); + return new WebDriverTimeouts($this->executor, $this->w3cCompliant); } /** diff --git a/lib/WebDriverPoint.php b/lib/WebDriverPoint.php index 4e2dbd211..9600af9d8 100644 --- a/lib/WebDriverPoint.php +++ b/lib/WebDriverPoint.php @@ -36,7 +36,7 @@ public function __construct($x, $y) */ public function getX() { - return $this->x; + return (int) $this->x; } /** @@ -46,7 +46,7 @@ public function getX() */ public function getY() { - return $this->y; + return (int) $this->y; } /** diff --git a/lib/WebDriverTimeouts.php b/lib/WebDriverTimeouts.php index 6903f7080..eeba9a10e 100644 --- a/lib/WebDriverTimeouts.php +++ b/lib/WebDriverTimeouts.php @@ -27,10 +27,15 @@ class WebDriverTimeouts * @var ExecuteMethod */ protected $executor; + /** + * @var bool + */ + protected $w3cCompliant; - public function __construct(ExecuteMethod $executor) + public function __construct(ExecuteMethod $executor, $w3cCompliant = false) { $this->executor = $executor; + $this->w3cCompliant = $w3cCompliant; } /** @@ -41,6 +46,15 @@ public function __construct(ExecuteMethod $executor) */ public function implicitlyWait($seconds) { + if ($this->w3cCompliant) { + $this->executor->execute( + DriverCommand::IMPLICITLY_WAIT, + ['implicit' => $seconds * 1000] + ); + + return $this; + } + $this->executor->execute( DriverCommand::IMPLICITLY_WAIT, ['ms' => $seconds * 1000] @@ -57,6 +71,15 @@ public function implicitlyWait($seconds) */ public function setScriptTimeout($seconds) { + if ($this->w3cCompliant) { + $this->executor->execute( + DriverCommand::SET_SCRIPT_TIMEOUT, + ['script' => $seconds * 1000] + ); + + return $this; + } + $this->executor->execute( DriverCommand::SET_SCRIPT_TIMEOUT, ['ms' => $seconds * 1000] @@ -73,6 +96,15 @@ public function setScriptTimeout($seconds) */ public function pageLoadTimeout($seconds) { + if ($this->w3cCompliant) { + $this->executor->execute( + DriverCommand::SET_SCRIPT_TIMEOUT, + ['pageLoad' => $seconds * 1000] + ); + + return $this; + } + $this->executor->execute(DriverCommand::SET_TIMEOUT, [ 'type' => 'page load', 'ms' => $seconds * 1000, diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 90c072922..a2f6e9d0f 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -33,7 +33,10 @@ public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() $this->serverUrl, $this->desiredCapabilities, $this->connectionTimeout, - $this->requestTimeout + $this->requestTimeout, + null, + null, + null ); $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index eea14b6e5..066179f1f 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -61,4 +61,24 @@ public function testShouldFindMultipleElements() $this->assertCount(5, $elements); $this->assertContainsOnlyInstancesOf(RemoteWebElement::class, $elements); } + + public function testEscapeCssSelector() + { + if (getenv('GECKODRIVER') !== '1') { + $this->markTestSkipped( + 'CSS selectors containing special characters are not supported by the legacy protocol' + ); + } + + $this->driver->get($this->getTestPageUrl('escape_css.html')); + + $element = $this->driver->findElement(WebDriverBy::id('.fo\'oo')); + $this->assertSame('Foo', $element->getText()); + + $element = $this->driver->findElement(WebDriverBy::className('#ba\'r')); + $this->assertSame('Bar', $element->getText()); + + $element = $this->driver->findElement(WebDriverBy::name('.#ba\'z')); + $this->assertSame('Baz', $element->getText()); + } } diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index d996d304a..9105aa93f 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -77,7 +77,11 @@ public function testShouldGetSessionId() */ public function testShouldGetAllSessions() { - $sessions = RemoteWebDriver::getAllSessions($this->serverUrl); + if (getenv('GECKODRIVER') === '1') { + $this->markTestSkipped('"getAllSessions" is not supported by the W3C specification'); + } + + $sessions = RemoteWebDriver::getAllSessions($this->serverUrl, 30000); $this->assertInternalType('array', $sessions); $this->assertCount(1, $sessions); @@ -94,12 +98,22 @@ public function testShouldGetAllSessions() */ public function testShouldQuitAndUnsetExecutor() { - $this->assertCount(1, RemoteWebDriver::getAllSessions($this->serverUrl)); + if (getenv('GECKODRIVER') === '1') { + $this->markTestSkipped('"getAllSessions" is not supported by the W3C specification'); + } + + $this->assertCount( + 1, + RemoteWebDriver::getAllSessions($this->serverUrl, 30000) + ); $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); $this->driver->quit(); - $this->assertCount(0, RemoteWebDriver::getAllSessions($this->serverUrl)); + $this->assertCount( + 0, + RemoteWebDriver::getAllSessions($this->serverUrl, 30000) + ); $this->assertNull($this->driver->getCommandExecutor()); } @@ -136,6 +150,9 @@ public function testShouldCloseWindow() $this->driver->get($this->getTestPageUrl('open_new_window.html')); $this->driver->findElement(WebDriverBy::cssSelector('a'))->click(); + // Mandatory for Geckodriver + $this->driver->wait()->until(WebDriverExpectedCondition::numberOfWindowsToBe(2)); + $this->assertCount(2, $this->driver->getWindowHandles()); $this->driver->close(); diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index d4614a431..a4684ace3 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -272,6 +272,10 @@ public function testShouldSubmitFormByClickOnSubmitInput() */ public function testShouldCompareEqualsElement() { + if (getenv('GECKODRIVER') === '1') { + $this->markTestSkipped('"equals" is not supported by the W3C specification'); + } + $this->driver->get($this->getTestPageUrl('index.html')); $firstElement = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 3df984810..b2bd51835 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -46,10 +46,16 @@ public function testShouldClickOnElement() ->click($element) ->perform(); - $this->assertSame( - ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1'], - $this->retrieveLoggedEvents() - ); + $logs = ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1']; + $loggedEvents = $this->retrieveLoggedEvents(); + + if ('1' === getenv('GECKODRIVER')) { + $loggedEvents = array_slice($loggedEvents, 0, count($logs)); + // Firefox sometimes triggers some extra events + // it's not related to Geckodriver, it's Firefox's own behavior + } + + $this->assertSame($logs, $loggedEvents); } /** @@ -71,10 +77,12 @@ public function testShouldClickAndHoldOnElementAndRelease() ->release() ->perform(); - $this->assertSame( - ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1'], - $this->retrieveLoggedEvents() - ); + if ('1' === getenv('GECKODRIVER')) { + $logs = ['mouseover item-1', 'mousedown item-1', 'dragstart item-1']; + } else { + $logs = ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1']; + } + $this->assertSame($logs, $this->retrieveLoggedEvents()); } /** diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 5fe6a7e8a..7a0f8af23 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -58,6 +58,8 @@ protected function setUp() // --no-sandbox is a workaround for Chrome crashing: https://github.com/SeleniumHQ/selenium/issues/4961 $chromeOptions->addArguments(['--headless', 'window-size=1024,768', '--no-sandbox']); $this->desiredCapabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); + } elseif (getenv('GECKODRIVER') === '1') { + $this->serverUrl = 'http://localhost:4444/'; } $this->desiredCapabilities->setBrowserName($browserName); @@ -68,7 +70,10 @@ protected function setUp() $this->serverUrl, $this->desiredCapabilities, $this->connectionTimeout, - $this->requestTimeout + $this->requestTimeout, + null, + null, + null ); } } diff --git a/tests/functional/web/escape_css.html b/tests/functional/web/escape_css.html new file mode 100644 index 000000000..48213084a --- /dev/null +++ b/tests/functional/web/escape_css.html @@ -0,0 +1,14 @@ + + + + + Test CSS selector escaping + + + +
    Foo
    +
    Bar
    +
    Baz
    + + + diff --git a/tests/functional/web/upload.html b/tests/functional/web/upload.html index 65a622c50..6762873c3 100644 --- a/tests/functional/web/upload.html +++ b/tests/functional/web/upload.html @@ -8,7 +8,7 @@

    - +

    From 4a65bed00dd2bdbbfa81206590df29d2060221c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Aug 2019 16:18:50 +0200 Subject: [PATCH 254/600] Add back Geckodriver to the Travis matrix --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 47ddb461e..906951171 100644 --- a/.travis.yml +++ b/.travis.yml @@ -108,9 +108,14 @@ install: before_script: - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; CHROMEDRIVER_VERSION=$(wget -qO- "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"); wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi + - if [ "$GECKODRIVER" = "1" ]; then mkdir geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux64.tar.gz; tar xzf geckodriver-v0.24.0-linux64.tar.gz -C geckodriver; fi - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.8.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; fi - - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.8.1.jar -enablePassThrough false -log ./logs/selenium.log & + - if [ "$GECKODRIVER" = "1" ]; then + geckodriver/geckodriver &> ./logs/geckodriver.log & + else + java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.8.1.jar -enablePassThrough false -log ./logs/selenium.log & + fi - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" @@ -124,6 +129,7 @@ script: after_script: - if [ -f ./logs/selenium.log ]; then cat ./logs/selenium.log; fi - if [ -f ./logs/php-server.log ]; then cat ./logs/php-server.log; fi + - if [ -f ./logs/geckodriver.log ]; then cat ./logs/geckodriver.log; fi after_success: - travis_retry php vendor/bin/php-coveralls -v From 5729355c5d37953d6a1a5a2f55afc7ba1c23bf57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Aug 2019 17:06:26 +0200 Subject: [PATCH 255/600] Improve tests stability --- tests/functional/WebDriverActionsTest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index b2bd51835..1f03c8899 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -78,11 +78,13 @@ public function testShouldClickAndHoldOnElementAndRelease() ->perform(); if ('1' === getenv('GECKODRIVER')) { - $logs = ['mouseover item-1', 'mousedown item-1', 'dragstart item-1']; + $this->assertArraySubset(['mouseover item-1', 'mousedown item-1'], $this->retrieveLoggedEvents()); } else { - $logs = ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1']; + $this->assertSame( + ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1'], + $this->retrieveLoggedEvents() + ); } - $this->assertSame($logs, $this->retrieveLoggedEvents()); } /** From 721a7c2737ea8353c01e76ec7752aa0751e667eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 4 Nov 2019 19:36:50 +0000 Subject: [PATCH 256/600] Use latest geckodriver --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 906951171..950e8fe64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -108,7 +108,7 @@ install: before_script: - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; CHROMEDRIVER_VERSION=$(wget -qO- "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"); wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - - if [ "$GECKODRIVER" = "1" ]; then mkdir geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux64.tar.gz; tar xzf geckodriver-v0.24.0-linux64.tar.gz -C geckodriver; fi + - if [ "$GECKODRIVER" = "1" ]; then mkdir geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz; tar xzf geckodriver-v0.26.0-linux64.tar.gz -C geckodriver; fi - sh -e /etc/init.d/xvfb start - if [ ! -f jar/selenium-server-standalone-3.8.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; fi - if [ "$GECKODRIVER" = "1" ]; then From 71a6698227485b368d4212980ed9efcde15b292f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 5 Nov 2019 15:35:40 +0000 Subject: [PATCH 257/600] Make POST body always valid JSON in W3C mode --- lib/Remote/HttpCommandExecutor.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index c783b2892..8114d7817 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -313,8 +313,13 @@ public function execute(WebDriverCommand $command) $encoded_params = null; - if ($http_method === 'POST' && $params && is_array($params)) { - $encoded_params = json_encode($params); + if ($http_method === 'POST') { + if ($params && is_array($params)) { + $encoded_params = json_encode($params); + } elseif ($this->w3cCompliant) { + // POST body must be valid JSON in W3C, even if empty: https://www.w3.org/TR/webdriver/#processing-model + $encoded_params = '{}'; + } } curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params); From 7119d7fc97c5291768cd8632a15bfa7d75bff145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 5 Nov 2019 15:37:36 +0000 Subject: [PATCH 258/600] Codestyle: unify casing in w3c methods --- lib/Remote/HttpCommandExecutor.php | 12 +++---- lib/Remote/JsonWireCompat.php | 8 ++--- lib/Remote/RemoteMouse.php | 20 ++++++------ lib/Remote/RemoteTargetLocator.php | 4 +-- lib/Remote/RemoteWebDriver.php | 30 +++++++++--------- lib/Remote/RemoteWebElement.php | 50 ++++++++++++++++-------------- lib/WebDriverOptions.php | 8 ++--- lib/WebDriverTimeouts.php | 12 +++---- 8 files changed, 74 insertions(+), 70 deletions(-) diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 8114d7817..b87c94069 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -171,7 +171,7 @@ class HttpCommandExecutor implements WebDriverCommandExecutor /** * @var bool */ - protected $w3cCompliant = true; + protected $isW3cCompliant = true; /** * @param string $url @@ -208,9 +208,9 @@ public function __construct($url, $http_proxy = null, $http_proxy_port = null) $this->setConnectionTimeout(30000); } - public function disableW3CCompliance() + public function disableW3cCompliance() { - $this->w3cCompliant = false; + $this->isW3cCompliant = false; } /** @@ -262,12 +262,12 @@ public function execute(WebDriverCommand $command) { $commandName = $command->getName(); if (!isset(self::$commands[$commandName])) { - if ($this->w3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) { + if ($this->isW3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) { throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); } } - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $raw = self::$w3cCompliantCommands[$command->getName()]; } else { $raw = self::$commands[$command->getName()]; @@ -316,7 +316,7 @@ public function execute(WebDriverCommand $command) if ($http_method === 'POST') { if ($params && is_array($params)) { $encoded_params = json_encode($params); - } elseif ($this->w3cCompliant) { + } elseif ($this->isW3cCompliant) { // POST body must be valid JSON in W3C, even if empty: https://www.w3.org/TR/webdriver/#processing-model $encoded_params = '{}'; } diff --git a/lib/Remote/JsonWireCompat.php b/lib/Remote/JsonWireCompat.php index 78b9cba0e..3488b8604 100644 --- a/lib/Remote/JsonWireCompat.php +++ b/lib/Remote/JsonWireCompat.php @@ -44,16 +44,16 @@ public static function getElement(array $rawElement) /** * @param WebDriverBy $by - * @param bool $w3cCompliant + * @param bool $isW3cCompliant * * @return array */ - public static function getUsing(WebDriverBy $by, $w3cCompliant) + public static function getUsing(WebDriverBy $by, $isW3cCompliant) { $mechanism = $by->getMechanism(); $value = $by->getValue(); - if ($w3cCompliant) { + if ($isW3cCompliant) { switch ($mechanism) { // Convert to CSS selectors case 'class name': @@ -89,7 +89,7 @@ private static function escapeSelector($selector) { return preg_replace_callback('/[^a-z0-9]/iSu', function ($matches) { $chr = $matches[0]; - if (mb_strlen($chr) == 1) { + if (mb_strlen($chr) === 1) { $ord = ord($chr); } else { $chr = mb_convert_encoding($chr, 'UTF-32BE', 'UTF-8'); diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index aa0d59829..4bd4a849b 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -30,16 +30,16 @@ class RemoteMouse implements WebDriverMouse /** * @var bool */ - private $w3cCompliant; + private $isW3cCompliant; /** * @param RemoteExecuteMethod $executor - * @param bool $w3cCompliant + * @param bool $isW3cCompliant */ - public function __construct(RemoteExecuteMethod $executor, $w3cCompliant = false) + public function __construct(RemoteExecuteMethod $executor, $isW3cCompliant = false) { $this->executor = $executor; - $this->w3cCompliant = $w3cCompliant; + $this->isW3cCompliant = $isW3cCompliant; } /** @@ -49,7 +49,7 @@ public function __construct(RemoteExecuteMethod $executor, $w3cCompliant = false */ public function click(WebDriverCoordinates $where = null) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $moveAction = $where ? [$this->createMoveAction($where)] : []; $this->executor->execute(DriverCommand::ACTIONS, [ 'actions' => [ @@ -80,7 +80,7 @@ public function click(WebDriverCoordinates $where = null) */ public function contextClick(WebDriverCoordinates $where = null) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $moveAction = $where ? [$this->createMoveAction($where)] : []; $this->executor->execute(DriverCommand::ACTIONS, [ 'actions' => [ @@ -122,7 +122,7 @@ public function contextClick(WebDriverCoordinates $where = null) */ public function doubleClick(WebDriverCoordinates $where = null) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $clickActions = $this->createClickActions(); $moveAction = null === $where ? [] : [$this->createMoveAction($where)]; $this->executor->execute(DriverCommand::ACTIONS, [ @@ -152,7 +152,7 @@ public function doubleClick(WebDriverCoordinates $where = null) */ public function mouseDown(WebDriverCoordinates $where = null) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute(DriverCommand::ACTIONS, [ 'actions' => [ [ @@ -192,7 +192,7 @@ public function mouseMove( $x_offset = null, $y_offset = null ) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute(DriverCommand::ACTIONS, [ 'actions' => [ [ @@ -230,7 +230,7 @@ public function mouseMove( */ public function mouseUp(WebDriverCoordinates $where = null) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $moveAction = $where ? [$this->createMoveAction($where)] : []; $this->executor->execute(DriverCommand::ACTIONS, [ diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 55a879c0d..8bd89ef44 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -112,8 +112,8 @@ public function activeElement() $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []); $method = new RemoteExecuteMethod($this->driver); - $w3cCompliant = $this->driver instanceof RemoteWebDriver ? $this->driver->isW3cCompliant() : false; + $isW3cCompliant = ($this->driver instanceof RemoteWebDriver) ? $this->driver->isW3cCompliant() : false; - return new RemoteWebElement($method, JsonWireCompat::getElement($response), $w3cCompliant); + return new RemoteWebElement($method, JsonWireCompat::getElement($response), $isW3cCompliant); } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 6d3a7d833..4d3573c0c 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -62,23 +62,23 @@ class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInpu /** * @var bool */ - protected $w3cCompliant; + protected $isW3cCompliant; /** * @param HttpCommandExecutor $commandExecutor * @param string $sessionId * @param WebDriverCapabilities|null $capabilities - * @param bool $w3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec + * @param bool $isW3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec */ protected function __construct( HttpCommandExecutor $commandExecutor, $sessionId, WebDriverCapabilities $capabilities = null, - $w3cCompliant = false + $isW3cCompliant = false ) { $this->executor = $commandExecutor; $this->sessionID = $sessionId; - $this->w3cCompliant = $w3cCompliant; + $this->isW3cCompliant = $isW3cCompliant; if ($capabilities !== null) { $this->capabilities = $capabilities; @@ -168,7 +168,7 @@ public static function create( $value = $response->getValue(); if (!$w3c_compliant = isset($value['capabilities'])) { - $executor->disableW3CCompliance(); + $executor->disableW3cCompliance(); } $returnedCapabilities = new DesiredCapabilities($w3c_compliant ? $value['capabilities'] : $value); @@ -232,7 +232,7 @@ public function findElement(WebDriverBy $by) { $raw_element = $this->execute( DriverCommand::FIND_ELEMENT, - JsonWireCompat::getUsing($by, $this->w3cCompliant) + JsonWireCompat::getUsing($by, $this->isW3cCompliant) ); return $this->newElement(JsonWireCompat::getElement($raw_element)); @@ -249,7 +249,7 @@ public function findElements(WebDriverBy $by) { $raw_elements = $this->execute( DriverCommand::FIND_ELEMENTS, - JsonWireCompat::getUsing($by, $this->w3cCompliant) + JsonWireCompat::getUsing($by, $this->isW3cCompliant) ); $elements = []; @@ -428,7 +428,7 @@ public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) */ public function manage() { - return new WebDriverOptions($this->getExecuteMethod(), $this->w3cCompliant); + return new WebDriverOptions($this->getExecuteMethod(), $this->isW3cCompliant); } /** @@ -459,7 +459,7 @@ public function switchTo() public function getMouse() { if (!$this->mouse) { - $this->mouse = new RemoteMouse($this->getExecuteMethod(), $this->w3cCompliant); + $this->mouse = new RemoteMouse($this->getExecuteMethod(), $this->isW3cCompliant); } return $this->mouse; @@ -605,7 +605,7 @@ public function execute($command_name, $params = []) */ public function isW3cCompliant() { - return $this->w3cCompliant; + return $this->isW3cCompliant; } /** @@ -620,10 +620,12 @@ protected function prepareScriptArguments(array $arguments) foreach ($arguments as $key => $value) { if ($value instanceof WebDriverElement) { $args[$key] = [ - $this->w3cCompliant ? JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER : 'ELEMENT' => $value->getID(), + $this->isW3cCompliant ? + JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER + : 'ELEMENT' => $value->getID(), ]; } else { - if (\is_array($value)) { + if (is_array($value)) { $value = $this->prepareScriptArguments($value); } $args[$key] = $value; @@ -653,7 +655,7 @@ protected function getExecuteMethod() */ protected function newElement($id) { - return new RemoteWebElement($this->getExecuteMethod(), $id, $this->w3cCompliant); + return new RemoteWebElement($this->getExecuteMethod(), $id, $this->isW3cCompliant); } /** @@ -669,7 +671,7 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities return new DesiredCapabilities(); } - if (\is_array($desired_capabilities)) { + if (is_array($desired_capabilities)) { return new DesiredCapabilities($desired_capabilities); } diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index b07b18227..75dfa3ba2 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -46,19 +46,19 @@ class RemoteWebElement implements WebDriverElement, WebDriverLocatable /** * @var bool */ - protected $w3cCompliant; + protected $isW3cCompliant; /** * @param RemoteExecuteMethod $executor * @param string $id - * @param bool $w3cCompliant + * @param bool $isW3cCompliant */ - public function __construct(RemoteExecuteMethod $executor, $id, $w3cCompliant = false) + public function __construct(RemoteExecuteMethod $executor, $id, $isW3cCompliant = false) { $this->executor = $executor; $this->id = $id; $this->fileDetector = new UselessFileDetector(); - $this->w3cCompliant = $w3cCompliant; + $this->isW3cCompliant = $isW3cCompliant; } /** @@ -73,20 +73,22 @@ public function clear() [':id' => $this->id] ); - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute(DriverCommand::ACTIONS, [ - 'actions' => [[ - 'type' => 'key', - 'id' => 'keyboard', - 'actions' => [ - ['type' => 'keyDown' , 'value' => WebDriverKeys::CONTROL], - ['type' => 'keyDown' , 'value' => 'a'], - ['type' => 'keyUp' , 'value' => WebDriverKeys::CONTROL], - ['type' => 'keyUp' , 'value' => 'a'], - ['type' => 'keyDown' , 'value' => WebDriverKeys::BACKSPACE], - ['type' => 'keyUp' , 'value' => WebDriverKeys::BACKSPACE], + 'actions' => [ + [ + 'type' => 'key', + 'id' => 'keyboard', + 'actions' => [ + ['type' => 'keyDown', 'value' => WebDriverKeys::CONTROL], + ['type' => 'keyDown', 'value' => 'a'], + ['type' => 'keyUp', 'value' => WebDriverKeys::CONTROL], + ['type' => 'keyUp', 'value' => 'a'], + ['type' => 'keyDown', 'value' => WebDriverKeys::BACKSPACE], + ['type' => 'keyUp', 'value' => WebDriverKeys::BACKSPACE], + ], ], - ]], + ], ]); } @@ -118,7 +120,7 @@ public function click() */ public function findElement(WebDriverBy $by) { - $params = JsonWireCompat::getUsing($by, $this->w3cCompliant); + $params = JsonWireCompat::getUsing($by, $this->isW3cCompliant); $params[':id'] = $this->id; $raw_element = $this->executor->execute( @@ -139,7 +141,7 @@ public function findElement(WebDriverBy $by) */ public function findElements(WebDriverBy $by) { - $params = JsonWireCompat::getUsing($by, $this->w3cCompliant); + $params = JsonWireCompat::getUsing($by, $this->isW3cCompliant); $params[':id'] = $this->id; $raw_elements = $this->executor->execute( DriverCommand::FIND_CHILD_ELEMENTS, @@ -167,7 +169,7 @@ public function getAttribute($attribute_name) ':id' => $this->id, ]; - if ($this->w3cCompliant && ($attribute_name === 'value' || $attribute_name === 'index')) { + if ($this->isW3cCompliant && ($attribute_name === 'value' || $attribute_name === 'index')) { $value = $this->executor->execute(DriverCommand::GET_ELEMENT_PROPERTY, $params); if ($value === true) { @@ -357,7 +359,7 @@ public function sendKeys($value) { $local_file = $this->fileDetector->getLocalFile($value); if ($local_file === null) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $params = [ 'text' => (string) $value, ':id' => $this->id, @@ -374,7 +376,7 @@ public function sendKeys($value) return $this; } - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $params = [ 'text' => $local_file, ':id' => $this->id, @@ -420,7 +422,7 @@ public function setFileDetector(FileDetector $detector) */ public function submit() { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute(DriverCommand::EXECUTE_SCRIPT, [ // cannot call the submit method directly in case an input of this form is named "submit" 'script' => sprintf( @@ -459,7 +461,7 @@ public function getID() */ public function equals(WebDriverElement $other) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { throw new UnsupportedOperationException('"elementEquals" is not supported by the W3C specification'); } @@ -478,7 +480,7 @@ public function equals(WebDriverElement $other) */ protected function newElement($id) { - return new static($this->executor, $id, $this->w3cCompliant); + return new static($this->executor, $id, $this->isW3cCompliant); } /** diff --git a/lib/WebDriverOptions.php b/lib/WebDriverOptions.php index 4c584bd07..682918a17 100644 --- a/lib/WebDriverOptions.php +++ b/lib/WebDriverOptions.php @@ -31,12 +31,12 @@ class WebDriverOptions /** * @var bool */ - protected $w3cCompliant; + protected $isW3cCompliant; - public function __construct(ExecuteMethod $executor, $w3cCompliant = false) + public function __construct(ExecuteMethod $executor, $isW3cCompliant = false) { $this->executor = $executor; - $this->w3cCompliant = $w3cCompliant; + $this->isW3cCompliant = $isW3cCompliant; } /** @@ -133,7 +133,7 @@ public function getCookies() */ public function timeouts() { - return new WebDriverTimeouts($this->executor, $this->w3cCompliant); + return new WebDriverTimeouts($this->executor, $this->isW3cCompliant); } /** diff --git a/lib/WebDriverTimeouts.php b/lib/WebDriverTimeouts.php index eeba9a10e..5735cb48d 100644 --- a/lib/WebDriverTimeouts.php +++ b/lib/WebDriverTimeouts.php @@ -30,12 +30,12 @@ class WebDriverTimeouts /** * @var bool */ - protected $w3cCompliant; + protected $isW3cCompliant; - public function __construct(ExecuteMethod $executor, $w3cCompliant = false) + public function __construct(ExecuteMethod $executor, $isW3cCompliant = false) { $this->executor = $executor; - $this->w3cCompliant = $w3cCompliant; + $this->isW3cCompliant = $isW3cCompliant; } /** @@ -46,7 +46,7 @@ public function __construct(ExecuteMethod $executor, $w3cCompliant = false) */ public function implicitlyWait($seconds) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute( DriverCommand::IMPLICITLY_WAIT, ['implicit' => $seconds * 1000] @@ -71,7 +71,7 @@ public function implicitlyWait($seconds) */ public function setScriptTimeout($seconds) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute( DriverCommand::SET_SCRIPT_TIMEOUT, ['script' => $seconds * 1000] @@ -96,7 +96,7 @@ public function setScriptTimeout($seconds) */ public function pageLoadTimeout($seconds) { - if ($this->w3cCompliant) { + if ($this->isW3cCompliant) { $this->executor->execute( DriverCommand::SET_SCRIPT_TIMEOUT, ['pageLoad' => $seconds * 1000] From bd34170cb3c17322dbc785fede30b6c88ffd651c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 28 Oct 2019 18:21:02 +0100 Subject: [PATCH 259/600] Compatibility with Symfony 5 --- CHANGELOG.md | 1 + composer.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e733516..e2662351d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Changed - Revert no longer needed workaround for Chromedriver bug [2943](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943). +- Allow installation of Symfony 5 components. ## 1.7.1 - 2019-06-13 ### Fixed diff --git a/composer.json b/composer.json index 2a9929725..3a841a504 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "minimum-stability": "beta", "require": { "php": "^5.6 || ~7.0", - "symfony/process": "^2.8 || ^3.1 || ^4.0", + "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0", "ext-curl": "*", "ext-zip": "*", "ext-mbstring": "*", @@ -26,7 +26,7 @@ "squizlabs/php_codesniffer": "^2.6", "php-mock/php-mock-phpunit": "^1.1", "php-coveralls/php-coveralls": "^2.0", - "symfony/var-dumper": "^3.3 || ^4.0", + "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0", "jakub-onderka/php-parallel-lint": "^0.9.2" }, "suggest": { From e9277912d553971c2b73bf19df3fb44323f1f8b7 Mon Sep 17 00:00:00 2001 From: Mohammadreza Yektamaram Date: Tue, 1 Oct 2019 14:51:24 +0330 Subject: [PATCH 260/600] Minor grammar fixes --- README.md | 2 +- example.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b25bee453..0fa9db31c 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ We have a great community willing to help you! - **Via our Facebook Group** - If you have questions or are an active contributor consider joining our [facebook group](https://www.facebook.com/groups/phpwebdriver/) and contribute to communal discussion and support - **Via StackOverflow** - You can also [ask a question](https://stackoverflow.com/questions/ask?tags=php+selenium-webdriver) or find many already answered question on StackOverflow -- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/facebook/php-webdriver/issues/new) as an new issue +- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/facebook/php-webdriver/issues/new) as a new issue ## Contributing diff --git a/example.php b/example.php index f1109ed54..4dbb93900 100644 --- a/example.php +++ b/example.php @@ -23,7 +23,7 @@ require_once('vendor/autoload.php'); -// start Chrome with 5 second timeout +// start Chrome with 5 seconds timeout $host = 'http://localhost:4444/wd/hub'; // this is the default $capabilities = DesiredCapabilities::chrome(); $driver = RemoteWebDriver::create($host, $capabilities, 5000); From a21b3c82dabb8a777e81aed5a8239cba67efc115 Mon Sep 17 00:00:00 2001 From: "Benjamin R. White" Date: Tue, 27 Feb 2018 17:21:16 +0000 Subject: [PATCH 261/600] Allow combined not() and presenceOfElementLocated() functionality --- CHANGELOG.md | 3 +++ lib/WebDriverExpectedCondition.php | 9 ++++--- tests/unit/WebDriverExpectedConditionTest.php | 24 ++++++++++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2662351d..bbd2f4d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Revert no longer needed workaround for Chromedriver bug [2943](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943). - Allow installation of Symfony 5 components. +### Fixed +- `WebDriverExpectedCondition::presenceOfElementLocated()` works correctly when used within `WebDriverExpectedCondition::not()`. + ## 1.7.1 - 2019-06-13 ### Fixed - Error `Call to a member function toArray()` if capabilities were already converted to an array. diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 15c7b3d2d..4bab4707b 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -148,7 +148,11 @@ public static function presenceOfElementLocated(WebDriverBy $by) { return new static( function (WebDriver $driver) use ($by) { - return $driver->findElement($by); + try { + return $driver->findElement($by); + } catch (NoSuchElementException $e) { + return false; + } } ); } @@ -423,8 +427,7 @@ function (WebDriver $driver) use ($by, $text) { */ public static function elementToBeClickable(WebDriverBy $by) { - $visibility_of_element_located = - self::visibilityOfElementLocated($by); + $visibility_of_element_located = self::visibilityOfElementLocated($by); return new static( function (WebDriver $driver) use ($visibility_of_element_located) { diff --git a/tests/unit/WebDriverExpectedConditionTest.php b/tests/unit/WebDriverExpectedConditionTest.php index 8cd4203a9..6dde484ef 100644 --- a/tests/unit/WebDriverExpectedConditionTest.php +++ b/tests/unit/WebDriverExpectedConditionTest.php @@ -135,6 +135,28 @@ public function testShouldDetectPresenceOfElementLocatedCondition() $this->assertSame($element, $this->wait->until($condition)); } + public function testShouldDetectNotPresenceOfElementLocatedCondition() + { + $element = new RemoteWebElement(new RemoteExecuteMethod($this->driverMock), 'id'); + + $this->driverMock->expects($this->at(0)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willReturn($element); + + $this->driverMock->expects($this->at(1)) + ->method('findElement') + ->with($this->isInstanceOf(WebDriverBy::class)) + ->willThrowException(new NoSuchElementException('')); + + $condition = WebDriverExpectedCondition::not( + WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector('.foo')) + ); + + $this->assertFalse(call_user_func($condition->getApply(), $this->driverMock)); + $this->assertTrue(call_user_func($condition->getApply(), $this->driverMock)); + } + public function testShouldDetectPresenceOfAllElementsLocatedByCondition() { $element = $this->createMock(RemoteWebElement::class); @@ -160,7 +182,7 @@ public function testShouldDetectVisibilityOfElementLocatedCondition() // Call #1: throws NoSuchElementException // Call #2: return Element, but isDisplayed will throw StaleElementReferenceException // Call #3: return Element, but isDisplayed will return false - // Call #4: return Element, isDisplayed will true and condition will match + // Call #4: return Element, isDisplayed will return true and condition will match $element = $this->createMock(RemoteWebElement::class); $element->expects($this->at(0)) From 1f8d242f98310b12d8dbfc39859aad6b13f35708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 1 Oct 2018 12:16:55 +0200 Subject: [PATCH 262/600] Use polyfill-mbstring when ext-mbstring isn't available --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3a841a504..e5aef5a03 100644 --- a/composer.json +++ b/composer.json @@ -14,9 +14,9 @@ "require": { "php": "^5.6 || ~7.0", "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0", + "symfony/polyfill-mbstring": "^1.12", "ext-curl": "*", "ext-zip": "*", - "ext-mbstring": "*", "ext-json": "*" }, "require-dev": { From dc50f3f0fd5506230f4fcc48670bf1edcf1d65ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Nov 2019 00:04:33 +0100 Subject: [PATCH 263/600] Skipped tests must be completely excluded from Saucelabs to avoid starting the driver there, otherwise the build is not marked passed on Saucelabs dashboard --- tests/functional/RemoteWebDriverFindElementTest.php | 3 +++ tests/functional/WebDriverActionsTest.php | 1 + 2 files changed, 4 insertions(+) diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 066179f1f..2eb3e38c7 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -62,6 +62,9 @@ public function testShouldFindMultipleElements() $this->assertContainsOnlyInstancesOf(RemoteWebElement::class, $elements); } + /** + * @group exclude-saucelabs + */ public function testEscapeCssSelector() { if (getenv('GECKODRIVER') !== '1') { diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 1f03c8899..07af88085 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -88,6 +88,7 @@ public function testShouldClickAndHoldOnElementAndRelease() } /** + * @group exclude-saucelabs * @covers ::__construct * @covers ::contextClick * @covers ::perform From a29494a551b8efb8afef51dc4f7af2cb7af98d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 10 Nov 2019 23:01:03 +0100 Subject: [PATCH 264/600] Add Chromedriver Travis build (without Selenium server proxy) --- .travis.yml | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 950e8fe64..986df3e31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,8 @@ env: matrix: include: # Codestyle check build - - php: '7.3' + - name: 'Code style and static analysis' + php: '7.3' env: CHECK_CODESTYLE=1 before_install: - phpenv config-rm xdebug.ini @@ -30,18 +31,19 @@ matrix: after_success: ~ # Build with lowest possible dependencies on lowest possible PHP - - php: '5.6' + - name: 'Lowest dependencies build' + php: '5.6' env: DEPENDENCIES="--prefer-lowest" # Firefox inside Travis environment - - name: 'Firefox 45 on Travis (OSS protocol)' + - name: 'Firefox 45 on Travis (OSS protocol); via Selenium server' php: '7.3' env: BROWSER_NAME="firefox" addons: firefox: "45.8.0esr" # Firefox with Geckodriver (W3C mode) inside Travis environment - - name: 'Firefox latest on Travis (W3C protocol)' + - name: 'Firefox latest on Travis (W3C protocol); no Selenium server' php: 7.3 env: - BROWSER_NAME="firefox" @@ -49,9 +51,22 @@ matrix: addons: firefox: latest - # Stable Chrome + Chromedriver inside Travis environment - - php: '7.3' - env: BROWSER_NAME="chrome" CHROME_HEADLESS="1" + # Stable Chrome + Chromedriver inside Travis environment via Selenium server proxy + - name: 'Chrome stable on Travis; via Selenium server' + php: '7.3' + env: + - BROWSER_NAME="chrome" + - CHROME_HEADLESS="1" + addons: + chrome: stable + + # Stable Chrome + Chromedriver inside Travis environment directly via Chromedriver + - name: 'Chrome stable on Travis; no Selenium server' + php: '7.3' + env: + - BROWSER_NAME="chrome" + - CHROME_HEADLESS="1" + - CHROMEDRIVER="1" addons: chrome: stable @@ -113,6 +128,8 @@ before_script: - if [ ! -f jar/selenium-server-standalone-3.8.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; fi - if [ "$GECKODRIVER" = "1" ]; then geckodriver/geckodriver &> ./logs/geckodriver.log & + elif [ "$CHROMEDRIVER" = "1" ]; then + chromedriver/chromedriver --port=4444 --url-base=/wd/hub &> ./logs/chromedriver.log & else java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.8.1.jar -enablePassThrough false -log ./logs/selenium.log & fi @@ -130,6 +147,7 @@ after_script: - if [ -f ./logs/selenium.log ]; then cat ./logs/selenium.log; fi - if [ -f ./logs/php-server.log ]; then cat ./logs/php-server.log; fi - if [ -f ./logs/geckodriver.log ]; then cat ./logs/geckodriver.log; fi + - if [ -f ./logs/chromedriver.log ]; then cat ./logs/chromedriver.log; fi after_success: - travis_retry php vendor/bin/php-coveralls -v From 61ab881143846201c314bc9f9988a8831a75f26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 10 Nov 2019 23:51:18 +0100 Subject: [PATCH 265/600] Use newer Selenium server where possible But we can easily update only to 3.14.0 (latest version which includes HtmlUnit). However update to 3.14.159 should be done soon (but HtmlUnit needs to be sideloaded). --- .travis.yml | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 986df3e31..fc7368965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ env: global: - DISPLAY=:99.0 - BROWSER_NAME="htmlunit" + - SELENIUM_SERVER="https://selenium-release.storage.googleapis.com/3.14/selenium-server-standalone-3.14.0.jar" # Latest version including HtmlUnit matrix: include: @@ -36,9 +37,11 @@ matrix: env: DEPENDENCIES="--prefer-lowest" # Firefox inside Travis environment - - name: 'Firefox 45 on Travis (OSS protocol); via Selenium server' + - name: 'Firefox 45 on Travis (OSS protocol); via legacy Selenium server' php: '7.3' - env: BROWSER_NAME="firefox" + env: + - BROWSER_NAME="firefox" + - SELENIUM_SERVER="legacy" addons: firefox: "45.8.0esr" @@ -114,7 +117,6 @@ matrix: cache: directories: - $HOME/.composer/cache - - jar install: - travis_retry composer self-update @@ -123,15 +125,24 @@ install: before_script: - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; CHROMEDRIVER_VERSION=$(wget -qO- "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"); wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - - if [ "$GECKODRIVER" = "1" ]; then mkdir geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz; tar xzf geckodriver-v0.26.0-linux64.tar.gz -C geckodriver; fi - - sh -e /etc/init.d/xvfb start - - if [ ! -f jar/selenium-server-standalone-3.8.1.jar ]; then wget -q -t 3 -P jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; fi + - if [ "$GECKODRIVER" = "1" ]; then mkdir -p geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz; tar xzf geckodriver-v0.26.0-linux64.tar.gz -C geckodriver; fi + - sh -e /etc/init.d/xvfb start # TODO: start only when needed (ie. not in headless mode) + - if [ ! -f jar/selenium-server-standalone.jar ] && [ -n "$SELENIUM_SERVER" ]; then + mkdir -p jar; + if [ "$SELENIUM_SERVER" = "legacy" ]; then + wget -q -t 3 -O jar/selenium-server-standalone.jar https://selenium-release.storage.googleapis.com/3.8/selenium-server-standalone-3.8.1.jar; + else + wget -q -t 3 -O jar/selenium-server-standalone.jar $SELENIUM_SERVER; + fi + fi - if [ "$GECKODRIVER" = "1" ]; then geckodriver/geckodriver &> ./logs/geckodriver.log & elif [ "$CHROMEDRIVER" = "1" ]; then chromedriver/chromedriver --port=4444 --url-base=/wd/hub &> ./logs/chromedriver.log & + elif [ "$SELENIUM_SERVER" = "legacy" ]; then + java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$PWD/chromedriver/chromedriver" -jar jar/selenium-server-standalone.jar -enablePassThrough false -log ./logs/selenium.log & else - java -Dwebdriver.firefox.marionette=false -Dwebdriver.chrome.driver="$CHROMEDRIVER_PATH" -jar jar/selenium-server-standalone-3.8.1.jar -enablePassThrough false -log ./logs/selenium.log & + java -Dwebdriver.chrome.driver="$PWD/chromedriver/chromedriver" -Dwebdriver.gecko.driver="$PWD/geckodriver/geckodriver" -jar jar/selenium-server-standalone.jar -log ./logs/selenium.log & fi - until $(echo | nc localhost 4444); do sleep 1; echo Waiting for Selenium server on port 4444...; done; echo "Selenium server started" - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & From a4b0d7130ed35c2083f62ae0bb135c563df68364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Nov 2019 10:21:11 +0100 Subject: [PATCH 266/600] Convert W3C invalid capabilities to corresponding ones This avoids `Facebook\WebDriver\Exception\UnknownServerException: Illegal key values seen in w3c capabilities: [chromeOptions]` error with new Selenium server. This conversion is necessary to maintain BC - simply renaming chromeOptions to goog:chromeOptions will break capabilities with Chromedriver <2.31. --- lib/Chrome/ChromeOptions.php | 7 ++++++- lib/Remote/RemoteWebDriver.php | 32 ++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/lib/Chrome/ChromeOptions.php b/lib/Chrome/ChromeOptions.php index 901dc5388..949d6708b 100644 --- a/lib/Chrome/ChromeOptions.php +++ b/lib/Chrome/ChromeOptions.php @@ -25,9 +25,14 @@ class ChromeOptions { /** - * The key of chrome options in desired capabilities. + * The key of chrome options desired capabilities (in legacy OSS JsonWire protocol) + * @deprecated */ const CAPABILITY = 'chromeOptions'; + /** + * The key of chrome options desired capabilities (in W3C compatible protocol) + */ + const CAPABILITY_W3C = 'goog:chromeOptions'; /** * @var array */ diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 4d3573c0c..c87a572f9 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -140,15 +140,15 @@ public static function create( // W3C $parameters = [ 'capabilities' => [ - 'firstMatch' => [$desired_capabilities->toArray()], + 'firstMatch' => [static::convertCapabilitiesToW3c($desired_capabilities->toArray())], ], ]; - // Legacy protocol - if (null !== $required_capabilities && $required_capabilities_array = $required_capabilities->toArray()) { - $parameters['capabilities']['alwaysMatch'] = $required_capabilities_array; + if ($required_capabilities !== null && $required_capabilities_array = $required_capabilities->toArray()) { + $parameters['capabilities']['alwaysMatch'] = static::convertCapabilitiesToW3c($required_capabilities_array); } + // Legacy protocol if ($required_capabilities !== null) { // TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities. // This has changed with the W3C WebDriver spec, but is the only way how to pass these @@ -677,4 +677,28 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities return $desired_capabilities; } + + /** + * Convert keys invalid in W3C capabilities to corresponding ones for W3C. + * + * @param array $capabilitiesArray + * @return array + */ + protected static function convertCapabilitiesToW3c(array $capabilitiesArray) + { + if (array_key_exists(ChromeOptions::CAPABILITY, $capabilitiesArray)) { + if (array_key_exists(ChromeOptions::CAPABILITY_W3C, $capabilitiesArray)) { + $capabilitiesArray[ChromeOptions::CAPABILITY_W3C] = array_merge( + $capabilitiesArray[ChromeOptions::CAPABILITY], + $capabilitiesArray[ChromeOptions::CAPABILITY_W3C] + ); + } else { + $capabilitiesArray[ChromeOptions::CAPABILITY_W3C] = $capabilitiesArray[ChromeOptions::CAPABILITY]; + } + + unset($capabilitiesArray[ChromeOptions::CAPABILITY]); + } + + return $capabilitiesArray; + } } From 3597a6bcaddb2a462d71cf81620346892991ad47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Nov 2019 10:37:25 +0100 Subject: [PATCH 267/600] =?UTF-8?q?Enable=20W3C=20protocol=20for=20Chromed?= =?UTF-8?q?river=20=F0=9F=8E=89=20#469?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, W3C was forcily disabled for Chromedriver using Capabilities on startup. As we now experimentaly support W3C protocol, this is no longer needed. If W3C is detected during initial handshake, the browser will be started using W3C dialect (otherwise it will use legacy OSS JsonWire protocol). --- lib/Remote/RemoteWebDriver.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index c87a572f9..d2e302f44 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -112,23 +112,6 @@ public static function create( $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities); - // Hotfix: W3C WebDriver protocol is not yet supported by php-webdriver, so we must force Chromedriver to - // not use the W3C protocol by default (which is what Chromedriver does starting with version 75). - if ($desired_capabilities->getBrowserName() === WebDriverBrowserType::CHROME - && mb_strpos($selenium_server_url, 'browserstack') === false // see https://github.com/facebook/php-webdriver/issues/644 - ) { - $currentChromeOptions = $desired_capabilities->getCapability(ChromeOptions::CAPABILITY); - $chromeOptions = !empty($currentChromeOptions) ? $currentChromeOptions : new ChromeOptions(); - - if ($chromeOptions instanceof ChromeOptions && !isset($chromeOptions->toArray()['w3c'])) { - $chromeOptions->setExperimentalOption('w3c', false); - } elseif (is_array($chromeOptions) && !isset($chromeOptions['w3c'])) { - $chromeOptions['w3c'] = false; - } - - $desired_capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); - } - $executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port); if ($connection_timeout_in_ms !== null) { $executor->setConnectionTimeout($connection_timeout_in_ms); From a9685bf2aa22de07d97ca93ff452e5016ee3141d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Nov 2019 12:41:45 +0100 Subject: [PATCH 268/600] Add JsonWire travis build on Chromedriver to make sure we won't break the old protocol --- .travis.yml | 19 +++++++++++++++---- tests/functional/WebDriverTestCase.php | 5 +++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc7368965..4a8a268a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,8 +54,8 @@ matrix: addons: firefox: latest - # Stable Chrome + Chromedriver inside Travis environment via Selenium server proxy - - name: 'Chrome stable on Travis; via Selenium server' + # Stable Chrome + Chromedriver (W3C mode) inside Travis environment via Selenium server proxy + - name: 'Chrome stable on Travis (W3C protocol); via Selenium server' php: '7.3' env: - BROWSER_NAME="chrome" @@ -63,8 +63,8 @@ matrix: addons: chrome: stable - # Stable Chrome + Chromedriver inside Travis environment directly via Chromedriver - - name: 'Chrome stable on Travis; no Selenium server' + # Stable Chrome + Chromedriver (W3C mode) inside Travis environment directly via Chromedriver + - name: 'Chrome stable on Travis (W3C protocol); no Selenium server' php: '7.3' env: - BROWSER_NAME="chrome" @@ -73,6 +73,17 @@ matrix: addons: chrome: stable + # Stable Chrome + Chromedriver (JsonWire OSS mode) inside Travis environment directly via Chromedriver + - name: 'Chrome stable on Travis (OSS protocol); no Selenium server' + php: '7.3' + env: + - BROWSER_NAME="chrome" + - CHROME_HEADLESS="1" + - CHROMEDRIVER="1" + - DISABLE_W3C_PROTOCOL="1" + addons: + chrome: stable + # Saucelabs builds - php: '7.3' env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 7a0f8af23..920eb86a7 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -57,6 +57,11 @@ protected function setUp() $chromeOptions = new ChromeOptions(); // --no-sandbox is a workaround for Chrome crashing: https://github.com/SeleniumHQ/selenium/issues/4961 $chromeOptions->addArguments(['--headless', 'window-size=1024,768', '--no-sandbox']); + + if (getenv('DISABLE_W3C_PROTOCOL')) { + $chromeOptions->setExperimentalOption('w3c', false); + } + $this->desiredCapabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); } elseif (getenv('GECKODRIVER') === '1') { $this->serverUrl = 'http://localhost:4444/'; From 041658be9e1284578f5fba1198b10dc8922ceb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Nov 2019 13:25:45 +0100 Subject: [PATCH 269/600] Improve W3C builds detection in conditionally-run tests --- .../RemoteWebDriverFindElementTest.php | 8 +++--- tests/functional/RemoteWebDriverTest.php | 1 - tests/functional/RemoteWebElementTest.php | 4 +-- tests/functional/WebDriverActionsTest.php | 4 +-- tests/functional/WebDriverTestCase.php | 26 +++++++++++++++++++ 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 2eb3e38c7..c5671b497 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -67,11 +67,9 @@ public function testShouldFindMultipleElements() */ public function testEscapeCssSelector() { - if (getenv('GECKODRIVER') !== '1') { - $this->markTestSkipped( - 'CSS selectors containing special characters are not supported by the legacy protocol' - ); - } + self::skipForJsonWireProtocol( + 'CSS selectors containing special characters are not supported by the legacy protocol' + ); $this->driver->get($this->getTestPageUrl('escape_css.html')); diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 9105aa93f..72fc30505 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -150,7 +150,6 @@ public function testShouldCloseWindow() $this->driver->get($this->getTestPageUrl('open_new_window.html')); $this->driver->findElement(WebDriverBy::cssSelector('a'))->click(); - // Mandatory for Geckodriver $this->driver->wait()->until(WebDriverExpectedCondition::numberOfWindowsToBe(2)); $this->assertCount(2, $this->driver->getWindowHandles()); diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index a4684ace3..52877dcda 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -272,9 +272,7 @@ public function testShouldSubmitFormByClickOnSubmitInput() */ public function testShouldCompareEqualsElement() { - if (getenv('GECKODRIVER') === '1') { - $this->markTestSkipped('"equals" is not supported by the W3C specification'); - } + self::skipForW3cProtocol('"equals" is not supported by the W3C specification'); $this->driver->get($this->getTestPageUrl('index.html')); diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 07af88085..9798f6e5a 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -49,7 +49,7 @@ public function testShouldClickOnElement() $logs = ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1']; $loggedEvents = $this->retrieveLoggedEvents(); - if ('1' === getenv('GECKODRIVER')) { + if (getenv('GECKODRIVER') === '1') { $loggedEvents = array_slice($loggedEvents, 0, count($logs)); // Firefox sometimes triggers some extra events // it's not related to Geckodriver, it's Firefox's own behavior @@ -77,7 +77,7 @@ public function testShouldClickAndHoldOnElementAndRelease() ->release() ->perform(); - if ('1' === getenv('GECKODRIVER')) { + if (self::isW3cProtocolBuild()) { $this->assertArraySubset(['mouseover item-1', 'mousedown item-1'], $this->retrieveLoggedEvents()); } else { $this->assertSame( diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 920eb86a7..8b35a7700 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -102,6 +102,32 @@ public static function isSauceLabsBuild() return getenv('SAUCELABS') ? true : false; } + /** + * @return bool + */ + public static function isW3cProtocolBuild() + { + return getenv('GECKODRIVER') === '1' + || (getenv('BROWSER_NAME') === 'chrome' + && getenv('DISABLE_W3C_PROTOCOL') !== '1' + && !self::isSauceLabsBuild()); + } + + public static function skipForW3cProtocol($message = 'Not supported by W3C specification') + { + if (static::isW3cProtocolBuild()) { + static::markTestSkipped($message); + } + } + + public static function skipForJsonWireProtocol($message = 'Not supported by JsonWire protocol') + { + if (getenv('GECKODRIVER') !== '1' + && (getenv('CHROMEDRIVER') !== '1' || getenv('DISABLE_W3C_PROTOCOL') === '1')) { + static::markTestSkipped($message); + } + } + /** * Get the URL of given test HTML on running webserver. * From d249dea3f0da638c2d44c028b4a5d9247cc2fa87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 11 Nov 2019 16:36:05 +0100 Subject: [PATCH 270/600] Update changelog and readme to let the world know about W3C protocol experimental support --- CHANGELOG.md | 3 +++ README.md | 38 ++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbd2f4d52..b83a21743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added +- Experimental W3C WebDriver protocol support. The protocol will be used automatically when remote end (like Geckodriver, newer Chromedriver etc.) supports it. + ### Changed - Revert no longer needed workaround for Chromedriver bug [2943](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943). - Allow installation of Symfony 5 components. diff --git a/README.md b/README.md index 0fa9db31c..71742583b 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,16 @@ ## Description Php-webdriver library is PHP language binding for Selenium WebDriver, which allows you to control web browsers from PHP. -This library is compatible with Selenium server version 2.x and 3.x. -It implements the [JsonWireProtocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol), which is currently supported -by the Selenium server and will also implement the [W3C WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) specification in the future. +This library is compatible with Selenium server version 2.x, 3.x and 4.x. + +The library supports [JsonWireProtocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol) and also +implements **experimental support** of [W3C WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html). +The W3C WebDriver support is not yet full-featured, however it should allow to control Firefox via Geckodriver and new +versions of Chrome and Chromedriver with just a slight limitations. The concepts of this library are very similar to the "official" Java, .NET, Python and Ruby bindings from the [Selenium project](https://github.com/SeleniumHQ/selenium/). -**As of 2013, this PHP client has been rewritten from scratch.** -Using the old version? Check out [Adam Goucher's fork](https://github.com/Element-34/php-webdriver) of it. - Looking for API documentation of php-webdriver? See [https://facebook.github.io/php-webdriver/](https://facebook.github.io/php-webdriver/latest/) Any complaints, questions, or ideas? Post them in the user group https://www.facebook.com/groups/phpwebdriver/. @@ -41,24 +41,25 @@ Then install the library: The required server is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html -Download and run the server by replacing # with the current server version. Keep in mind **you must have Java 8+ installed to run this command**. +Download and run the server by **replacing #** with the current server version. Keep in mind **you must have Java 8+ installed to run this command**. java -jar selenium-server-standalone-#.jar -**NOTE:** If using Firefox, see alternate command below. - ### Create a Browser Session When creating a browser session, be sure to pass the url of your running server. ```php // This would be the url of the host running the server-standalone.jar -$host = 'http://localhost:4444/wd/hub'; // this is the default +$host = 'http://localhost:4444/wd/hub'; // this is the default url and port where Selenium server starts ``` ##### Launch Chrome -Make sure to have latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) versions installed. +Install latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads). + +The `chromedriver` binary must be placed in system `PATH` directory, otherwise you must provide the path when starting Selenium server +(eg. `java -Dwebdriver.chrome.driver="/path/to/chromedriver" -jar selenium-server-standalone-#.jar`). ```php $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); @@ -66,14 +67,11 @@ $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); ##### Launch Firefox -Make sure to have latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases) installed. - -Because Firefox (and Geckodriver) only support the new W3C WebDriver protocol (which is yet to be implemented by php-webdriver - see [issue #469](https://github.com/facebook/php-webdriver/issues/469)), -the protocols must be translated by Selenium Server - this feature is *partially* available in Selenium Server versions 3.5.0-3.8.1 and you can enable it like this: +Install latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases). - java -jar selenium-server-standalone-3.8.1.jar -enablePassThrough false +The `geckodriver` binary must be placed in system `PATH` directory, otherwise you must provide the path when starting Selenium server +(eg. `java -Dwebdriver.gecko.driver="/path/to/geckodriver" -jar selenium-server-standalone-#.jar`). -Now you can start Firefox from your code: ```php $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); @@ -82,9 +80,9 @@ $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); ### Customize Desired Capabilities ```php -$desired_capabilities = DesiredCapabilities::firefox(); -$desired_capabilities->setCapability('acceptSslCerts', false); -$driver = RemoteWebDriver::create($host, $desired_capabilities); +$desiredCapabilities = DesiredCapabilities::firefox(); +$desiredCapabilities->setCapability('acceptSslCerts', false); +$driver = RemoteWebDriver::create($host, $desiredCapabilities); ``` * See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities for more details. From 42f82dd233ea52f64f36f143a57c6d6df89c22c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 12 Nov 2019 23:54:22 +0100 Subject: [PATCH 271/600] Define branch alias for version 1.8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e5aef5a03..a6aec98ae 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ }, "extra": { "branch-alias": { - "dev-community": "1.5-dev" + "dev-community": "1.8.x-dev" } } } From a6cad80b88fcb3c3823afe85d653d0c46c05944c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 14 Nov 2019 19:10:16 +0100 Subject: [PATCH 272/600] Add convertor to W3C compatible capabilities (fixes #676, part of #469) --- lib/Remote/DesiredCapabilities.php | 73 ++++++++++ lib/Remote/RemoteWebDriver.php | 31 +--- tests/unit/Remote/DesiredCapabilitiesTest.php | 137 ++++++++++++++++++ 3 files changed, 213 insertions(+), 28 deletions(-) diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 533c8873a..c78d2302b 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -178,6 +178,79 @@ public function toArray() return $this->capabilities; } + /** + * @return array + */ + public function toW3cCompatibleArray() + { + $ossToW3c = [ + WebDriverCapabilityType::PLATFORM => 'platformName', + WebDriverCapabilityType::VERSION => 'browserVersion', + WebDriverCapabilityType::ACCEPT_SSL_CERTS => 'acceptInsecureCerts', + ChromeOptions::CAPABILITY => ChromeOptions::CAPABILITY_W3C, + ]; + + $allowedW3cCapabilities = [ + 'browserName', + 'browserVersion', + 'platformName', + 'acceptInsecureCerts', + 'pageLoadStrategy', + 'proxy', + 'setWindowRect', + 'timeouts', + 'strictFileInteractability', + 'unhandledPromptBehavior', + ]; + + $ossCapabilities = $this->toArray(); + $w3cCapabilities = []; + + foreach ($ossCapabilities as $capabilityKey => $capabilityValue) { + // Copy already W3C compatible capabilities + if (in_array($capabilityKey, $allowedW3cCapabilities, true)) { + $w3cCapabilities[$capabilityKey] = $capabilityValue; + } + + // Convert capabilitites with changed name + if (array_key_exists($capabilityKey, $ossToW3c)) { + if ($capabilityKey === 'platform') { + $w3cCapabilities[$ossToW3c[$capabilityKey]] = mb_strtolower($capabilityValue); + } else { + $w3cCapabilities[$ossToW3c[$capabilityKey]] = $capabilityValue; + } + } + + // Copy vendor extensions + if (mb_strpos($capabilityKey, ':') !== false) { + $w3cCapabilities[$capabilityKey] = $capabilityValue; + } + } + + // Convert ChromeOptions + if (array_key_exists(ChromeOptions::CAPABILITY, $ossCapabilities)) { + if (array_key_exists(ChromeOptions::CAPABILITY_W3C, $ossCapabilities)) { + $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = array_merge_recursive( + $ossCapabilities[ChromeOptions::CAPABILITY], + $ossCapabilities[ChromeOptions::CAPABILITY_W3C] + ); + } else { + $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = $ossCapabilities[ChromeOptions::CAPABILITY]; + } + } + + // Convert Firefox profile + if (array_key_exists(FirefoxDriver::PROFILE, $ossCapabilities)) { + // Convert profile only if not already set in moz:firefoxOptions + if (!array_key_exists('moz:firefoxOptions', $ossCapabilities) + || !array_key_exists('profile', $ossCapabilities['moz:firefoxOptions'])) { + $w3cCapabilities['moz:firefoxOptions']['profile'] = $ossCapabilities[FirefoxDriver::PROFILE]; + } + } + + return $w3cCapabilities; + } + /** * @return static */ diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index d2e302f44..1762f44a8 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -15,7 +15,6 @@ namespace Facebook\WebDriver\Remote; -use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Interactions\WebDriverActions; use Facebook\WebDriver\JavaScriptExecutor; use Facebook\WebDriver\WebDriver; @@ -123,12 +122,12 @@ public static function create( // W3C $parameters = [ 'capabilities' => [ - 'firstMatch' => [static::convertCapabilitiesToW3c($desired_capabilities->toArray())], + 'firstMatch' => [$desired_capabilities->toW3cCompatibleArray()], ], ]; - if ($required_capabilities !== null && $required_capabilities_array = $required_capabilities->toArray()) { - $parameters['capabilities']['alwaysMatch'] = static::convertCapabilitiesToW3c($required_capabilities_array); + if ($required_capabilities !== null && !empty($required_capabilities->toArray())) { + $parameters['capabilities']['alwaysMatch'] = $required_capabilities->toW3cCompatibleArray(); } // Legacy protocol @@ -660,28 +659,4 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities return $desired_capabilities; } - - /** - * Convert keys invalid in W3C capabilities to corresponding ones for W3C. - * - * @param array $capabilitiesArray - * @return array - */ - protected static function convertCapabilitiesToW3c(array $capabilitiesArray) - { - if (array_key_exists(ChromeOptions::CAPABILITY, $capabilitiesArray)) { - if (array_key_exists(ChromeOptions::CAPABILITY_W3C, $capabilitiesArray)) { - $capabilitiesArray[ChromeOptions::CAPABILITY_W3C] = array_merge( - $capabilitiesArray[ChromeOptions::CAPABILITY], - $capabilitiesArray[ChromeOptions::CAPABILITY_W3C] - ); - } else { - $capabilitiesArray[ChromeOptions::CAPABILITY_W3C] = $capabilitiesArray[ChromeOptions::CAPABILITY]; - } - - unset($capabilitiesArray[ChromeOptions::CAPABILITY]); - } - - return $capabilitiesArray; - } } diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index 6e14ef044..4ef4a055a 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -15,6 +15,7 @@ namespace Facebook\WebDriver\Remote; +use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Firefox\FirefoxDriver; use Facebook\WebDriver\Firefox\FirefoxPreferences; use Facebook\WebDriver\Firefox\FirefoxProfile; @@ -130,4 +131,140 @@ public function testShouldSetupFirefoxProfileAndDisableReaderViewForFirefoxBrows $this->assertSame('false', $firefoxProfile->getPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED)); } + + /** + * @dataProvider provideW3cCapabilities + * @param DesiredCapabilities $inputJsonWireCapabilities + * @param array $expectedW3cCapabilities + */ + public function testShouldConvertCapabilitiesToW3cCompatible( + DesiredCapabilities $inputJsonWireCapabilities, + array $expectedW3cCapabilities + ) { + $this->assertEquals( + $expectedW3cCapabilities, + $inputJsonWireCapabilities->toW3cCompatibleArray() + ); + } + + /** + * @return array[] + */ + public function provideW3cCapabilities() + { + $chromeOptions = new ChromeOptions(); + $chromeOptions->addArguments([ + '--headless', + ]); + + $firefoxProfileEncoded = (new FirefoxProfile())->encode(); + + return [ + 'changed name' => [ + new DesiredCapabilities([ + WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME, + WebDriverCapabilityType::VERSION => '67.0.1', + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::LINUX, + WebDriverCapabilityType::ACCEPT_SSL_CERTS => true, + ]), + [ + 'browserName' => 'chrome', + 'browserVersion' => '67.0.1', + 'platformName' => 'linux', + 'acceptInsecureCerts' => true, + ], + ], + 'removed capabilitites' => [ + new DesiredCapabilities([ + WebDriverCapabilityType::WEB_STORAGE_ENABLED => true, + WebDriverCapabilityType::TAKES_SCREENSHOT => false, + ]), + [], + ], + 'custom invalid capability should be removed' => [ + new DesiredCapabilities([ + 'customInvalidCapability' => 'shouldBeRemoved', + ]), + [], + ], + 'already W3C capabilitites' => [ + new DesiredCapabilities([ + 'pageLoadStrategy' => 'eager', + 'strictFileInteractability' => false, + ]), + [ + 'pageLoadStrategy' => 'eager', + 'strictFileInteractability' => false, + ], + ], + 'custom vendor extension' => [ + new DesiredCapabilities([ + 'vendor:prefix' => 'vendor extension should be kept', + ]), + [ + 'vendor:prefix' => 'vendor extension should be kept', + ], + ], + 'chromeOptions should be converted' => [ + new DesiredCapabilities([ + ChromeOptions::CAPABILITY => $chromeOptions, + ]), + [ + 'goog:chromeOptions' => [ + 'args' => ['--headless'], + 'binary' => '', + ], + ], + ], + 'chromeOptions should be merged if already defined' => [ + new DesiredCapabilities([ + ChromeOptions::CAPABILITY => $chromeOptions, + ChromeOptions::CAPABILITY_W3C => [ + 'debuggerAddress' => '127.0.0.1:38947', + 'args' => ['window-size=1024,768'], + ], + ]), + [ + 'goog:chromeOptions' => [ + 'args' => ['--headless', 'window-size=1024,768'], + 'binary' => '', + 'debuggerAddress' => '127.0.0.1:38947', + ], + ], + ], + 'firefox_profile should be converted' => [ + new DesiredCapabilities([ + FirefoxDriver::PROFILE => $firefoxProfileEncoded, + ]), + [ + 'moz:firefoxOptions' => [ + 'profile' => $firefoxProfileEncoded, + ], + ], + ], + 'firefox_profile should not be overwritten if already present' => [ + new DesiredCapabilities([ + FirefoxDriver::PROFILE => $firefoxProfileEncoded, + 'moz:firefoxOptions' => ['profile' => 'w3cProfile'], + ]), + [ + 'moz:firefoxOptions' => [ + 'profile' => 'w3cProfile', + ], + ], + ], + 'firefox_profile should be merged with moz:firefoxOptions if they already exists' => [ + new DesiredCapabilities([ + FirefoxDriver::PROFILE => $firefoxProfileEncoded, + 'moz:firefoxOptions' => ['args' => ['-headless']], + ]), + [ + 'moz:firefoxOptions' => [ + 'profile' => $firefoxProfileEncoded, + 'args' => ['-headless'], + ], + ], + ], + ]; + } } From f81659eaa82820b7a55be5ac173f56188af186c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 15 Nov 2019 00:39:53 +0100 Subject: [PATCH 273/600] Run geckodriver tests in headless mode --- tests/functional/WebDriverTestCase.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 8b35a7700..1f125634e 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -65,6 +65,10 @@ protected function setUp() $this->desiredCapabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions); } elseif (getenv('GECKODRIVER') === '1') { $this->serverUrl = 'http://localhost:4444/'; + $this->desiredCapabilities->setCapability( + 'moz:firefoxOptions', + ['args' => ['-headless']] + ); } $this->desiredCapabilities->setBrowserName($browserName); From b4b82e2ccada9a7d251ae4703478e94b5b593370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 15 Nov 2019 00:38:54 +0100 Subject: [PATCH 274/600] Add W3C window size and position commands --- lib/Remote/HttpCommandExecutor.php | 9 ++- tests/functional/WebDriverWindowTest.php | 81 ++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/functional/WebDriverWindowTest.php diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index b87c94069..d137030a4 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -144,8 +144,9 @@ class HttpCommandExecutor implements WebDriverCommandExecutor DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/accept'], DriverCommand::ACTIONS => ['method' => 'POST', 'url' => '/session/:sessionId/actions'], DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/dismiss'], - DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'], DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/async'], + DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'], + DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'], DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window'], DriverCommand::GET_ELEMENT_LOCATION => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], DriverCommand::GET_ELEMENT_PROPERTY => [ @@ -154,11 +155,15 @@ class HttpCommandExecutor implements WebDriverCommandExecutor ], DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window/handles'], - DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'], + DriverCommand::GET_WINDOW_POSITION => ['method' => 'GET', 'url' => '/session/:sessionId/window/rect'], + DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/rect'], DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], + DriverCommand::MAXIMIZE_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/maximize'], DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert/text'], DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'], + DriverCommand::SET_WINDOW_SIZE => ['method' => 'POST', 'url' => '/session/:sessionId/window/rect'], + DriverCommand::SET_WINDOW_POSITION => ['method' => 'POST', 'url' => '/session/:sessionId/window/rect'], ]; /** * @var string diff --git a/tests/functional/WebDriverWindowTest.php b/tests/functional/WebDriverWindowTest.php new file mode 100644 index 000000000..ccf041b16 --- /dev/null +++ b/tests/functional/WebDriverWindowTest.php @@ -0,0 +1,81 @@ +driver->manage() + ->window() + ->getPosition(); + + $this->assertGreaterThanOrEqual(0, $position->getX()); + $this->assertGreaterThanOrEqual(0, $position->getY()); + } + + public function testShouldGetSize() + { + $size = $this->driver->manage() + ->window() + ->getSize(); + + $this->assertGreaterThan(0, $size->getWidth()); + $this->assertGreaterThan(0, $size->getHeight()); + } + + public function testShouldMaximizeWindow() + { + $sizeBefore = $this->driver->manage() + ->window() + ->getSize(); + + $this->driver->manage() + ->window() + ->maximize(); + + $sizeAfter = $this->driver->manage() + ->window() + ->getSize(); + + $this->assertGreaterThanOrEqual($sizeBefore->getWidth(), $sizeAfter->getWidth()); + $this->assertGreaterThanOrEqual($sizeBefore->getHeight(), $sizeAfter->getHeight()); + } + + public function testShouldSetSize() + { + $sizeBefore = $this->driver->manage() + ->window() + ->getSize(); + $this->assertNotSame(500, $sizeBefore->getWidth()); + $this->assertNotSame(666, $sizeBefore->getHeight()); + + $this->driver->manage() + ->window() + ->setSize(new WebDriverDimension(500, 666)); + + $sizeAfter = $this->driver->manage() + ->window() + ->getSize(); + + $this->assertSame(500, $sizeAfter->getWidth()); + $this->assertSame(666, $sizeAfter->getHeight()); + } + + public function testShouldSetWindowPosition() + { + $this->driver->manage() + ->window() + ->setPosition(new WebDriverPoint(33, 66)); + + $positionAfter = $this->driver->manage() + ->window() + ->getPosition(); + + $this->assertSame(33, $positionAfter->getX()); + $this->assertSame(66, $positionAfter->getY()); + } +} From c7ee5e1852b42d73bc597bb70a1b03344bdcb233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 15 Nov 2019 12:17:12 +0100 Subject: [PATCH 275/600] Exclude window tests on Saucelabs, because they are not sane --- tests/functional/WebDriverWindowTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/functional/WebDriverWindowTest.php b/tests/functional/WebDriverWindowTest.php index ccf041b16..8de61d3e8 100644 --- a/tests/functional/WebDriverWindowTest.php +++ b/tests/functional/WebDriverWindowTest.php @@ -7,6 +7,9 @@ */ class WebDriverWindowTest extends WebDriverTestCase { + /** + * @group exclude-saucelabs + */ public function testShouldGetPosition() { $position = $this->driver->manage() @@ -45,6 +48,9 @@ public function testShouldMaximizeWindow() $this->assertGreaterThanOrEqual($sizeBefore->getHeight(), $sizeAfter->getHeight()); } + /** + * @group exclude-saucelabs + */ public function testShouldSetSize() { $sizeBefore = $this->driver->manage() From e9f4ec88e7ed10388613aa8b05cf1e3f4d2231d3 Mon Sep 17 00:00:00 2001 From: Lctrs Date: Fri, 22 Nov 2019 00:38:58 +0100 Subject: [PATCH 276/600] Download a compatible version of chromedriver with chrome Following the [algorithm described on the official chromedriver website](https://chromedriver.chromium.org/downloads/version-selection) : > Here are the steps to select the version of ChromeDriver to download: > > - First, find out which version of Chrome you are using. Let's say you have Chrome 72.0.3626.81. > - Take the Chrome version number, remove the last part, and append the result to URL "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_". For example, with Chrome version 72.0.3626.81, you'd get a URL "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_72.0.3626". > - Use the URL created in the last step to retrieve a small file containing the version of ChromeDriver to use. For example, the above URL will get your a file containing "72.0.3626.69". (The actual number may change in the future, of course.) > - Use the version number retrieved from the previous step to construct the URL to download ChromeDriver. With version 72.0.3626.69, the URL would be "https://chromedriver.storage.googleapis.com/index.html?path=72.0.3626.69/". --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4a8a268a8..0340b80e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -134,7 +134,13 @@ install: - travis_retry composer update --no-interaction $DEPENDENCIES before_script: - - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; CHROMEDRIVER_VERSION=$(wget -qO- "https://chromedriver.storage.googleapis.com/LATEST_RELEASE"); wget -q -t 3 https://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip; unzip chromedriver_linux64 -d chromedriver; fi + - if [ "$BROWSER_NAME" = "chrome" ]; then + mkdir chromedriver; + CHROME_VERSION=$(google-chrome --product-version); + CHROME_VERSION=${CHROME_VERSION%.*}; + wget -q -t 3 https://chromedriver.storage.googleapis.com/$(curl -L https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_VERSION})/chromedriver_linux64.zip; + unzip chromedriver_linux64.zip -d chromedriver; + fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - if [ "$GECKODRIVER" = "1" ]; then mkdir -p geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz; tar xzf geckodriver-v0.26.0-linux64.tar.gz -C geckodriver; fi - sh -e /etc/init.d/xvfb start # TODO: start only when needed (ie. not in headless mode) From ee14c4392399a9fc7b362f488226141ca67e8348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 19 Nov 2019 13:14:34 +0100 Subject: [PATCH 277/600] Use W3C protocol on some Saucelabs builds --- .travis.yml | 20 +++++++------ tests/functional/WebDriverTestCase.php | 33 +++++++++++++++++----- tests/functional/WebDriverTimeoutsTest.php | 3 ++ 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0340b80e7..2c80cbb18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,8 +85,9 @@ matrix: chrome: stable # Saucelabs builds - - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" + - name: 'Sauce Labs, Firefox 47, OSS protocol' + php: '7.3' + env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" DISABLE_W3C_PROTOCOL="1" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" @@ -95,8 +96,9 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" # 74 is the last version which don't use W3C WebDriver by default + - name: 'Sauce Labs, Chrome 74, OSS protocol' + php: '7.3' + env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" DISABLE_W3C_PROTOCOL="1" # 74 is the last version which don't use W3C WebDriver by default before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" @@ -105,8 +107,9 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="75.0" PLATFORM="Windows 10" + - name: 'Sauce Labs, Chrome latest, W3C protocol' + php: '7.3' + env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" @@ -115,8 +118,9 @@ matrix: jwt: secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= - - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="16.16299" PLATFORM="Windows 10" + - name: 'Sauce Labs, Edge latest, W3C protocol' + php: '7.3' + env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="latest" PLATFORM="Windows 10" before_script: - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 1f125634e..f012d9068 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -112,9 +112,8 @@ public static function isSauceLabsBuild() public static function isW3cProtocolBuild() { return getenv('GECKODRIVER') === '1' - || (getenv('BROWSER_NAME') === 'chrome' - && getenv('DISABLE_W3C_PROTOCOL') !== '1' - && !self::isSauceLabsBuild()); + || (getenv('BROWSER_NAME') === 'chrome' && getenv('DISABLE_W3C_PROTOCOL') !== '1') + || getenv('BROWSER_NAME') === 'MicrosoftEdge'; } public static function skipForW3cProtocol($message = 'Not supported by W3C specification') @@ -153,12 +152,32 @@ protected function setUpSauceLabs() $this->desiredCapabilities->setBrowserName(getenv('BROWSER_NAME')); $this->desiredCapabilities->setVersion(getenv('VERSION')); $this->desiredCapabilities->setPlatform(getenv('PLATFORM')); - $this->desiredCapabilities->setCapability('name', get_class($this) . '::' . $this->getName()); - $this->desiredCapabilities->setCapability('tags', [get_class($this)]); + $name = get_class($this) . '::' . $this->getName(); + $tags = [get_class($this)]; if (getenv('TRAVIS_JOB_NUMBER')) { - $this->desiredCapabilities->setCapability('tunnel-identifier', getenv('TRAVIS_JOB_NUMBER')); - $this->desiredCapabilities->setCapability('build', getenv('TRAVIS_JOB_NUMBER')); + $tunnelIdentifier = getenv('TRAVIS_JOB_NUMBER'); + $build = getenv('TRAVIS_JOB_NUMBER'); + } + + if (!getenv('DISABLE_W3C_PROTOCOL')) { + $sauceOptions = [ + 'name' => $name, + 'tags' => $tags, + ]; + if (isset($tunnelIdentifier, $build)) { + $sauceOptions['tunnelIdentifier'] = $tunnelIdentifier; + $sauceOptions['build'] = $build; + } + $this->desiredCapabilities->setCapability('sauce:options', (object) $sauceOptions); + } else { + $this->desiredCapabilities->setCapability('name', $name); + $this->desiredCapabilities->setCapability('tags', $tags); + + if (isset($tunnelIdentifier, $build)) { + $this->desiredCapabilities->setCapability('tunnel-identifier', $tunnelIdentifier); + $this->desiredCapabilities->setCapability('build', $build); + } } } } diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index 733be545c..cd3e10d99 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -26,6 +26,9 @@ */ class WebDriverTimeoutsTest extends WebDriverTestCase { + /** + * @group exclude-saucelabs + */ public function testShouldFailGettingDelayedElementWithoutWait() { $this->driver->get($this->getTestPageUrl('delayed_element.html')); From a0d6be9a5fb351fe1a554bbd4f4a76f896727414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 19 Nov 2019 13:23:30 +0100 Subject: [PATCH 278/600] Simplify builds --- .travis.yml | 3 --- tests/functional/WebDriverAlertTest.php | 6 ------ tests/functional/WebDriverTestCase.php | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2c80cbb18..9bb73cc1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,7 +59,6 @@ matrix: php: '7.3' env: - BROWSER_NAME="chrome" - - CHROME_HEADLESS="1" addons: chrome: stable @@ -68,7 +67,6 @@ matrix: php: '7.3' env: - BROWSER_NAME="chrome" - - CHROME_HEADLESS="1" - CHROMEDRIVER="1" addons: chrome: stable @@ -78,7 +76,6 @@ matrix: php: '7.3' env: - BROWSER_NAME="chrome" - - CHROME_HEADLESS="1" - CHROMEDRIVER="1" - DISABLE_W3C_PROTOCOL="1" addons: diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index 163bee157..b99dad1fa 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -25,12 +25,6 @@ class WebDriverAlertTest extends WebDriverTestCase { protected function setUp() { - if (getenv('CHROME_HEADLESS') === '1') { - // Alerts in headless mode should be available in next Chrome version (61), see: - // https://bugs.chromium.org/p/chromium/issues/detail?id=718235 - $this->markTestSkipped('Alerts not yet supported by headless Chrome'); - } - parent::setUp(); $this->driver->get($this->getTestPageUrl('alert.html')); diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index f012d9068..9b302a1f3 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -113,7 +113,7 @@ public static function isW3cProtocolBuild() { return getenv('GECKODRIVER') === '1' || (getenv('BROWSER_NAME') === 'chrome' && getenv('DISABLE_W3C_PROTOCOL') !== '1') - || getenv('BROWSER_NAME') === 'MicrosoftEdge'; + || (self::isSauceLabsBuild() && getenv('DISABLE_W3C_PROTOCOL') !== '1'); } public static function skipForW3cProtocol($message = 'Not supported by W3C specification') From b54d50371b68926a60d2832db2ed94c1d3e95c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 23 Nov 2019 14:11:55 +0100 Subject: [PATCH 279/600] Skip tests utilizing xPath selectors, which are not properly supported in Edge --- tests/functional/WebDriverCheckboxesTest.php | 1 + tests/functional/WebDriverRadiosTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php index 48b72a53c..91513bd94 100644 --- a/tests/functional/WebDriverCheckboxesTest.php +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -20,6 +20,7 @@ /** * @covers \Facebook\WebDriver\WebDriverCheckboxes * @covers \Facebook\WebDriver\AbstractWebDriverCheckboxOrRadio + * @group exclude-edge */ class WebDriverCheckboxesTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php index 4d659772b..cf7b8378c 100644 --- a/tests/functional/WebDriverRadiosTest.php +++ b/tests/functional/WebDriverRadiosTest.php @@ -21,6 +21,7 @@ /** * @covers \Facebook\WebDriver\WebDriverRadios * @covers \Facebook\WebDriver\AbstractWebDriverCheckboxOrRadio + * @group exclude-edge */ class WebDriverRadiosTest extends WebDriverTestCase { From a419816547eed70cfcf54fd0763df33c94adcce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 23 Nov 2019 17:56:26 +0100 Subject: [PATCH 280/600] Skip file upload tests on Saucelabs, because W3C protocol does not support remote file upload See https://github.com/w3c/webdriver/issues/1355 --- lib/Remote/RemoteWebElement.php | 27 ++++++++++++--------------- tests/functional/FileUploadTest.php | 2 ++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 75dfa3ba2..33286504b 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -358,6 +358,7 @@ public function isSelected() public function sendKeys($value) { $local_file = $this->fileDetector->getLocalFile($value); + if ($local_file === null) { if ($this->isW3cCompliant) { $params = [ @@ -370,22 +371,18 @@ public function sendKeys($value) ':id' => $this->id, ]; } - - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); - - return $this; - } - - if ($this->isW3cCompliant) { - $params = [ - 'text' => $local_file, - ':id' => $this->id, - ]; } else { - $params = [ - 'value' => WebDriverKeys::encode($this->upload($local_file)), - ':id' => $this->id, - ]; + if ($this->isW3cCompliant) { + $params = [ + 'text' => $local_file, + ':id' => $this->id, + ]; + } else { + $params = [ + 'value' => WebDriverKeys::encode($this->upload($local_file)), + ':id' => $this->id, + ]; + } } $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); diff --git a/tests/functional/FileUploadTest.php b/tests/functional/FileUploadTest.php index 5b2f6d2d3..1029a2363 100644 --- a/tests/functional/FileUploadTest.php +++ b/tests/functional/FileUploadTest.php @@ -26,6 +26,8 @@ class FileUploadTest extends WebDriverTestCase /** * @group exclude-edge * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6052385/ + * @group exclude-saucelabs + * W3C protocol does not support remote file upload: https://github.com/w3c/webdriver/issues/1355 */ public function testShouldUploadAFile() { From 9d5623f40ab320601f8b2cee2bb463d722bb4393 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Mon, 25 Nov 2019 15:10:50 +0800 Subject: [PATCH 281/600] Fix mouseUp W3C action --- lib/Remote/RemoteMouse.php | 2 +- tests/functional/WebDriverActionsTest.php | 24 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index 4bd4a849b..6b7375834 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -241,7 +241,7 @@ public function mouseUp(WebDriverCoordinates $where = null) 'parameters' => ['pointerType' => 'mouse'], 'actions' => array_merge($moveAction, [ [ - 'type' => 'pointerDown', + 'type' => 'pointerUp', 'duration' => 0, 'button' => 0, ], diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 9798f6e5a..6799ef1d3 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -136,6 +136,30 @@ public function testShouldDoubleClickOnElement() $this->assertContains('dblclick item-3', $this->retrieveLoggedEvents()); } + /** + * @covers ::__construct + * @covers ::dragAndDrop + * @covers ::perform + */ + public function testShouldDragAndDrop() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $element = $this->driver->findElement(WebDriverBy::id('item-3')); + $target = $this->driver->findElement(WebDriverBy::id('item-1')); + + $this->driver->action() + ->dragAndDrop($element, $target) + ->perform(); + + $this->assertContains('mouseover item-3', $this->retrieveLoggedEvents()); + $this->assertContains('mousedown item-3', $this->retrieveLoggedEvents()); + $this->assertContains('mouseover item-1', $this->retrieveLoggedEvents()); + $this->assertContains('mouseup item-1', $this->retrieveLoggedEvents()); + } + /** * @return array */ From a94e33b99a8330c90c56128e430ffc55c507d304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 25 Nov 2019 17:13:57 +0100 Subject: [PATCH 282/600] Exclude unstable drag and drop test on SauceLabs --- tests/functional/WebDriverActionsTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 6799ef1d3..cb4359183 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -140,6 +140,7 @@ public function testShouldDoubleClickOnElement() * @covers ::__construct * @covers ::dragAndDrop * @covers ::perform + * @group exclude-saucelabs */ public function testShouldDragAndDrop() { From 574684f29b8d513ae213c4567f2f71da92734db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 24 Nov 2019 10:10:35 +0100 Subject: [PATCH 283/600] Add all W3C WebDriver exceptions --- .../ElementClickInterceptedException.php | 24 +++++ .../ElementNotInteractableException.php | 23 +++++ .../ElementNotSelectableException.php | 5 +- lib/Exception/ElementNotVisibleException.php | 3 + lib/Exception/ExpectedException.php | 3 + .../IMEEngineActivationFailedException.php | 3 + lib/Exception/IMENotAvailableException.php | 3 + lib/Exception/IndexOutOfBoundsException.php | 3 + .../InsecureCertificateException.php | 24 +++++ lib/Exception/InvalidArgumentException.php | 23 +++++ .../InvalidCookieDomainException.php | 3 + lib/Exception/InvalidCoordinatesException.php | 3 + .../InvalidElementStateException.php | 4 + lib/Exception/InvalidSelectorException.php | 3 + lib/Exception/InvalidSessionIdException.php | 24 +++++ lib/Exception/JavascriptErrorException.php | 23 +++++ .../MoveTargetOutOfBoundsException.php | 3 + lib/Exception/NoAlertOpenException.php | 5 +- lib/Exception/NoCollectionException.php | 3 + lib/Exception/NoScriptResultException.php | 3 + lib/Exception/NoStringException.php | 3 + lib/Exception/NoStringLengthException.php | 3 + lib/Exception/NoStringWrapperException.php | 3 + lib/Exception/NoSuchAlertException.php | 23 +++++ lib/Exception/NoSuchCollectionException.php | 3 + lib/Exception/NoSuchCookieException.php | 24 +++++ lib/Exception/NoSuchDocumentException.php | 5 +- lib/Exception/NoSuchDriverException.php | 3 + lib/Exception/NoSuchElementException.php | 3 + lib/Exception/NoSuchFrameException.php | 3 + lib/Exception/NoSuchWindowException.php | 3 + lib/Exception/NullPointerException.php | 3 + lib/Exception/ScriptTimeoutException.php | 3 + lib/Exception/SessionNotCreatedException.php | 3 + .../StaleElementReferenceException.php | 3 + lib/Exception/TimeoutException.php | 23 +++++ ...php => UnableToCaptureScreenException.php} | 5 +- lib/Exception/UnableToSetCookieException.php | 3 + .../UnexpectedAlertOpenException.php | 3 + .../UnexpectedJavascriptException.php | 5 +- lib/Exception/UnknownCommandException.php | 3 + lib/Exception/UnknownErrorException.php | 23 +++++ lib/Exception/UnknownMethodException.php | 23 +++++ lib/Exception/UnknownServerException.php | 5 +- .../UnsupportedOperationException.php | 3 + lib/Exception/WebDriverException.php | 92 ++++++++++++------- lib/Exception/XPathLookupException.php | 3 + lib/Net/URLChecker.php | 6 +- lib/WebDriverWait.php | 6 +- tests/functional/WebDriverAlertTest.php | 8 +- tests/functional/WebDriverTimeoutsTest.php | 6 +- .../unit/Exception/WebDriverExceptionTest.php | 49 ++++++++-- 52 files changed, 487 insertions(+), 55 deletions(-) create mode 100644 lib/Exception/ElementClickInterceptedException.php create mode 100644 lib/Exception/ElementNotInteractableException.php create mode 100644 lib/Exception/InsecureCertificateException.php create mode 100644 lib/Exception/InvalidArgumentException.php create mode 100644 lib/Exception/InvalidSessionIdException.php create mode 100644 lib/Exception/JavascriptErrorException.php create mode 100644 lib/Exception/NoSuchAlertException.php create mode 100644 lib/Exception/NoSuchCookieException.php create mode 100644 lib/Exception/TimeoutException.php rename lib/Exception/{TimeOutException.php => UnableToCaptureScreenException.php} (85%) create mode 100644 lib/Exception/UnknownErrorException.php create mode 100644 lib/Exception/UnknownMethodException.php diff --git a/lib/Exception/ElementClickInterceptedException.php b/lib/Exception/ElementClickInterceptedException.php new file mode 100644 index 000000000..e4b3a529e --- /dev/null +++ b/lib/Exception/ElementClickInterceptedException.php @@ -0,0 +1,24 @@ +driver->switchTo()->alert()->accept(); - $this->expectException(NoAlertOpenException::class); + if (self::isW3cProtocolBuild()) { + $this->expectException(NoSuchAlertException::class); + } else { + $this->expectException(NoAlertOpenException::class); + } + $this->driver->switchTo()->alert()->accept(); } diff --git a/tests/functional/WebDriverTimeoutsTest.php b/tests/functional/WebDriverTimeoutsTest.php index cd3e10d99..ca85075b8 100644 --- a/tests/functional/WebDriverTimeoutsTest.php +++ b/tests/functional/WebDriverTimeoutsTest.php @@ -17,7 +17,7 @@ use Facebook\WebDriver\Exception\NoSuchElementException; use Facebook\WebDriver\Exception\ScriptTimeoutException; -use Facebook\WebDriver\Exception\TimeOutException; +use Facebook\WebDriver\Exception\TimeoutException; use Facebook\WebDriver\Remote\RemoteWebElement; use Facebook\WebDriver\Remote\WebDriverBrowserType; @@ -65,8 +65,8 @@ public function testShouldFailIfPageIsLoadingLongerThanPageLoadTimeout() try { $this->driver->get($this->getTestPageUrl('slow_loading.html')); - $this->fail('ScriptTimeoutException or TimeOutException exception should be thrown'); - } catch (TimeOutException $e) { // thrown by Selenium 3.0.0+ + $this->fail('ScriptTimeoutException or TimeoutException exception should be thrown'); + } catch (TimeoutException $e) { // thrown by Selenium 3.0.0+ } catch (ScriptTimeoutException $e) { // thrown by Selenium 2 } } diff --git a/tests/unit/Exception/WebDriverExceptionTest.php b/tests/unit/Exception/WebDriverExceptionTest.php index f9aadd207..be3ab964c 100644 --- a/tests/unit/Exception/WebDriverExceptionTest.php +++ b/tests/unit/Exception/WebDriverExceptionTest.php @@ -29,14 +29,15 @@ public function testShouldStoreResultsOnInstantiation() } /** - * @dataProvider statusCodeProvider - * @param int $statusCode + * @dataProvider jsonWireStatusCodeProvider + * @dataProvider w3CWebDriverErrorCodeProvider + * @param int $errorCode * @param string $expectedExceptionType */ - public function testShouldThrowProperExceptionBasedOnSeleniumStatusCode($statusCode, $expectedExceptionType) + public function testShouldThrowProperExceptionBasedOnWebDriverErrorCode($errorCode, $expectedExceptionType) { try { - WebDriverException::throwException($statusCode, 'exception message', ['results']); + WebDriverException::throwException($errorCode, 'exception message', ['results']); } catch (WebDriverException $e) { $this->assertInstanceOf($expectedExceptionType, $e); @@ -48,7 +49,7 @@ public function testShouldThrowProperExceptionBasedOnSeleniumStatusCode($statusC /** * @return array[] */ - public function statusCodeProvider() + public function jsonWireStatusCodeProvider() { return [ [1337, UnrecognizedExceptionException::class], @@ -72,7 +73,7 @@ public function statusCodeProvider() [18, NoScriptResultException::class], [19, XPathLookupException::class], [20, NoSuchCollectionException::class], - [21, TimeOutException::class], + [21, TimeoutException::class], [22, NullPointerException::class], [23, NoSuchWindowException::class], [24, InvalidCookieDomainException::class], @@ -88,4 +89,40 @@ public function statusCodeProvider() [34, MoveTargetOutOfBoundsException::class], ]; } + + /** + * @return array[] + */ + public function w3CWebDriverErrorCodeProvider() + { + return [ + ['element click intercepted', ElementClickInterceptedException::class], + ['element not interactable', ElementNotInteractableException::class], + ['element not interactable', ElementNotInteractableException::class], + ['insecure certificate', InsecureCertificateException::class], + ['invalid argument', InvalidArgumentException::class], + ['invalid cookie domain', InvalidCookieDomainException::class], + ['invalid element state', InvalidElementStateException::class], + ['invalid selector', InvalidSelectorException::class], + ['invalid session id', InvalidSessionIdException::class], + ['javascript error', JavascriptErrorException::class], + ['move target out of bounds', MoveTargetOutOfBoundsException::class], + ['no such alert', NoSuchAlertException::class], + ['no such cookie', NoSuchCookieException::class], + ['no such element', NoSuchElementException::class], + ['no such frame', NoSuchFrameException::class], + ['no such window', NoSuchWindowException::class], + ['script timeout', ScriptTimeoutException::class], + ['session not created', SessionNotCreatedException::class], + ['stale element reference', StaleElementReferenceException::class], + ['timeout', TimeoutException::class], + ['unable to set cookie', UnableToSetCookieException::class], + ['unable to capture screen', UnableToCaptureScreenException::class], + ['unexpected alert open', UnexpectedAlertOpenException::class], + ['unknown command', UnknownCommandException::class], + ['unknown error', UnknownErrorException::class], + ['unknown method', UnknownMethodException::class], + ['unsupported operation', UnsupportedOperationException::class], + ]; + } } From 88fff59dac637265906d100fb91142d3f5475aca Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 21 Nov 2019 09:32:34 +0800 Subject: [PATCH 284/600] Pass W3C Compliance to RemoteTargetLocator --- lib/Remote/RemoteTargetLocator.php | 11 +++++++---- lib/Remote/RemoteWebDriver.php | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 8bd89ef44..1f8cb9270 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -33,11 +33,16 @@ class RemoteTargetLocator implements WebDriverTargetLocator * @var WebDriver */ protected $driver; + /** + * @var bool + */ + protected $isW3cCompliant; - public function __construct($executor, $driver) + public function __construct($executor, $driver, $isW3cCompliant = false) { $this->executor = $executor; $this->driver = $driver; + $this->isW3cCompliant = $isW3cCompliant; } /** @@ -112,8 +117,6 @@ public function activeElement() $response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []); $method = new RemoteExecuteMethod($this->driver); - $isW3cCompliant = ($this->driver instanceof RemoteWebDriver) ? $this->driver->isW3cCompliant() : false; - - return new RemoteWebElement($method, JsonWireCompat::getElement($response), $isW3cCompliant); + return new RemoteWebElement($method, JsonWireCompat::getElement($response), $this->isW3cCompliant); } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 1762f44a8..3164bad5e 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -432,7 +432,7 @@ public function navigate() */ public function switchTo() { - return new RemoteTargetLocator($this->getExecuteMethod(), $this); + return new RemoteTargetLocator($this->getExecuteMethod(), $this, $this->isW3cCompliant); } /** From 57f871eaa558b1108ece0fc4a713dd57796e4d50 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Wed, 20 Nov 2019 20:54:38 +0800 Subject: [PATCH 285/600] W3C switchToWindow takes a handle The W3C specification dictates that the parameter used to select the window should be named `handle`. Source: https://www.w3.org/TR/webdriver/#switch-to-window --- lib/Remote/RemoteTargetLocator.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index 1f8cb9270..7e8dbcd1f 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -89,7 +89,12 @@ public function frame($frame) */ public function window($handle) { - $params = ['name' => (string) $handle]; + if ($this->isW3cCompliant) { + $params = ['handle' => (string) $handle]; + } else { + $params = ['name' => (string) $handle]; + } + $this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params); return $this->driver; From 98686d91d96db975e1e22f6a8bdc5ccda2b54319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 25 Nov 2019 18:54:33 +0100 Subject: [PATCH 286/600] Add tests for switchTo()->window() of RemoteTargetLocator --- tests/functional/RemoteTargetLocatorTest.php | 55 ++++++++++++++++++++ tests/functional/WebDriverAlertTest.php | 1 + tests/functional/web/index.html | 2 + tests/functional/web/open_new_window.html | 2 +- 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/functional/RemoteTargetLocatorTest.php diff --git a/tests/functional/RemoteTargetLocatorTest.php b/tests/functional/RemoteTargetLocatorTest.php new file mode 100644 index 000000000..210e90b18 --- /dev/null +++ b/tests/functional/RemoteTargetLocatorTest.php @@ -0,0 +1,55 @@ +driver->get($this->getTestPageUrl('open_new_window.html')); + $originalWindowHandle = $this->driver->getWindowHandle(); + $windowHandlesBefore = $this->driver->getWindowHandles(); + + $this->driver->findElement(WebDriverBy::cssSelector('a#open-new-window')) + ->click(); + + $this->driver->wait()->until( + WebDriverExpectedCondition::numberOfWindowsToBe(2) + ); + + // At first the window should not be switched + $this->assertContains('open_new_window.html', $this->driver->getCurrentURL()); + $this->assertSame($originalWindowHandle, $this->driver->getWindowHandle()); + + /** + * @see https://w3c.github.io/webdriver/#get-window-handles + * > "The order in which the window handles are returned is arbitrary." + * Thus we must first find out which window handle is the new one + */ + $windowHandlesAfter = $this->driver->getWindowHandles(); + $newWindowHandle = array_diff($windowHandlesAfter, $windowHandlesBefore); + $newWindowHandle = reset($newWindowHandle); + + $this->driver->switchTo()->window($newWindowHandle); + + // After switchTo() is called, the active window should be changed + $this->assertContains('index.html', $this->driver->getCurrentURL()); + $this->assertNotSame($originalWindowHandle, $this->driver->getWindowHandle()); + } +} diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index b5fd3dec5..72d38d82a 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -21,6 +21,7 @@ /** * @covers \Facebook\WebDriver\WebDriverAlert + * @covers \Facebook\WebDriver\Remote\RemoteTargetLocator */ class WebDriverAlertTest extends WebDriverTestCase { diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index cf5b9c6c1..ff80fe025 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -11,6 +11,8 @@

    Welcome to the facebook/php-webdriver testing page.

    | Form with file upload | + Form with checkboxes and radios + | New window opener test page | Delayed render diff --git a/tests/functional/web/open_new_window.html b/tests/functional/web/open_new_window.html index b56e93d69..3c790226a 100644 --- a/tests/functional/web/open_new_window.html +++ b/tests/functional/web/open_new_window.html @@ -5,6 +5,6 @@ php-webdriver test page - open new window + open new window From 51353795e94ed34d23f2657bb690827a072ad14a Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 21 Nov 2019 08:32:22 +0800 Subject: [PATCH 287/600] Make GET_ACTIVE_ELEMENT a GET for W3C As defined in the specification 12.2.6: HTTP Method URI Template GET /session/{session id}/element/active Source: https://www.w3.org/TR/webdriver/#get-active-element --- lib/Remote/HttpCommandExecutor.php | 1 + tests/functional/RemoteTargetLocatorTest.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index d137030a4..a1b05c5ff 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -146,6 +146,7 @@ class HttpCommandExecutor implements WebDriverCommandExecutor DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/dismiss'], DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/async'], DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'], + DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'GET', 'url' => '/session/:sessionId/element/active'], DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'], DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window'], DriverCommand::GET_ELEMENT_LOCATION => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/rect'], diff --git a/tests/functional/RemoteTargetLocatorTest.php b/tests/functional/RemoteTargetLocatorTest.php index 210e90b18..becc194c8 100644 --- a/tests/functional/RemoteTargetLocatorTest.php +++ b/tests/functional/RemoteTargetLocatorTest.php @@ -15,6 +15,8 @@ namespace Facebook\WebDriver; +use Facebook\WebDriver\Remote\RemoteWebElement; + /** * @covers \Facebook\WebDriver\Remote\RemoteTargetLocator */ @@ -52,4 +54,21 @@ public function testShouldSwitchToWindow() $this->assertContains('index.html', $this->driver->getCurrentURL()); $this->assertNotSame($originalWindowHandle, $this->driver->getWindowHandle()); } + + /** + * @cover ::activeElement + */ + public function testActiveElement() + { + $this->driver->get($this->getTestPageUrl('index.html')); + + $activeElement = $this->driver->switchTo()->activeElement(); + $this->assertInstanceOf(RemoteWebElement::class, $activeElement); + $this->assertSame('body', $activeElement->getTagName()); + + $this->driver->findElement(WebDriverBy::name('test_name'))->click(); + $activeElement = $this->driver->switchTo()->activeElement(); + $this->assertSame('input', $activeElement->getTagName()); + $this->assertSame('test_name', $activeElement->getAttribute('name')); + } } From 1dcec4bcda282ae4ea6a4e1314a1cd3c953974d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 26 Nov 2019 17:12:40 +0100 Subject: [PATCH 288/600] Minor codestyle improvements and unifications --- .php_cs.dist | 10 +++++++++- phpstan.neon | 16 ++++++++-------- tests/functional/RemoteWebDriverCreateTest.php | 2 +- tests/functional/RemoteWebDriverTest.php | 2 +- tests/functional/WebDriverActionsTest.php | 2 +- tests/functional/WebDriverAlertTest.php | 2 +- tests/functional/WebDriverByTest.php | 7 +++++-- tests/functional/WebDriverCheckboxesTest.php | 14 +++++++------- tests/functional/WebDriverNavigationTest.php | 2 +- tests/functional/WebDriverRadiosTest.php | 14 +++++++------- tests/functional/WebDriverSelectTest.php | 9 ++++++--- tests/functional/WebDriverTimeoutsTest.php | 4 ++-- tests/unit/CookieTest.php | 4 ++-- tests/unit/Exception/WebDriverExceptionTest.php | 8 ++++---- .../WebDriverButtonReleaseActionTest.php | 4 ++-- .../Internal/WebDriverClickActionTest.php | 4 ++-- .../Internal/WebDriverClickAndHoldActionTest.php | 4 ++-- .../Internal/WebDriverContextClickActionTest.php | 4 ++-- .../Internal/WebDriverCoordinatesTest.php | 10 +++++----- .../Internal/WebDriverDoubleClickActionTest.php | 4 ++-- .../Internal/WebDriverKeyDownActionTest.php | 4 ++-- .../Internal/WebDriverKeyUpActionTest.php | 4 ++-- .../Internal/WebDriverMouseMoveActionTest.php | 4 ++-- .../WebDriverMouseToOffsetActionTest.php | 4 ++-- .../Internal/WebDriverSendKeysActionTest.php | 4 ++-- tests/unit/Remote/DesiredCapabilitiesTest.php | 6 +++--- tests/unit/Remote/HttpCommandExecutorTest.php | 6 +++--- tests/unit/Remote/RemoteWebDriverTest.php | 2 +- tests/unit/Support/XPathEscaperTest.php | 4 ++-- tests/unit/WebDriverOptionsTest.php | 2 +- 30 files changed, 90 insertions(+), 76 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 48aa29de7..b771f8b04 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -13,6 +13,8 @@ return PhpCsFixer\Config::create() 'concat_space' => ['spacing' => 'one'], 'function_typehint_space' => true, 'general_phpdoc_annotation_remove' => ['author'], + 'implode_call' => true, + 'is_null' => true, 'linebreak_after_opening_tag' => true, 'lowercase_cast' => true, 'mb_str_functions' => true, @@ -51,9 +53,15 @@ return PhpCsFixer\Config::create() 'ordered_imports' => true, 'php_unit_construct' => true, 'php_unit_dedicate_assert' => true, - 'php_unit_expectation' => true, + 'php_unit_expectation' => ['target' => '5.6'], + 'php_unit_method_casing' => ['case' => 'camel_case'], 'php_unit_mock' => true, + 'php_unit_mock_short_will_return' => true, + 'php_unit_namespaced' => ['target' => '5.7'], 'php_unit_no_expectation_annotation' => true, + 'php_unit_ordered_covers' => true, + 'php_unit_set_up_tear_down_visibility' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_indent' => true, 'phpdoc_no_access' => true, diff --git a/phpstan.neon b/phpstan.neon index 7023c466e..3ea02aee5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,10 +1,10 @@ parameters: - ignoreErrors: - - '#Class Symfony\\Component\\Process\\ProcessBuilder not found.#' - - '#Instantiated class Symfony\\Component\\Process\\ProcessBuilder not found.#' - - '#Call to method setPrefix\(\) on an unknown class Symfony\\Component\\Process\\ProcessBuilder#' + ignoreErrors: + - '#Class Symfony\\Component\\Process\\ProcessBuilder not found.#' + - '#Instantiated class Symfony\\Component\\Process\\ProcessBuilder not found.#' + - '#Call to method setPrefix\(\) on an unknown class Symfony\\Component\\Process\\ProcessBuilder#' # To be fixed: - - '#Call to an undefined method RecursiveIteratorIterator::getSubPathName\(\)#' - - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#' - - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::getCoordinates\(\)#' - - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::equals\(\)#' + - '#Call to an undefined method RecursiveIteratorIterator::getSubPathName\(\)#' + - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#' + - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::getCoordinates\(\)#' + - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::equals\(\)#' diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index a2f6e9d0f..5abec763b 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -20,8 +20,8 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; /** - * @covers \Facebook\WebDriver\Remote\RemoteWebDriver * @covers \Facebook\WebDriver\Remote\HttpCommandExecutor + * @covers \Facebook\WebDriver\Remote\RemoteWebDriver */ class RemoteWebDriverCreateTest extends WebDriverTestCase { diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 72fc30505..6f3becb0b 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -38,8 +38,8 @@ public function testShouldGetPageTitle() } /** - * @covers ::getCurrentURL * @covers ::get + * @covers ::getCurrentURL */ public function testShouldGetCurrentUrl() { diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index cb4359183..deb700575 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -61,8 +61,8 @@ public function testShouldClickOnElement() /** * @covers ::__construct * @covers ::clickAndHold - * @covers ::release * @covers ::perform + * @covers ::release */ public function testShouldClickAndHoldOnElementAndRelease() { diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index 72d38d82a..d6f5c91a2 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -20,8 +20,8 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @covers \Facebook\WebDriver\WebDriverAlert * @covers \Facebook\WebDriver\Remote\RemoteTargetLocator + * @covers \Facebook\WebDriver\WebDriverAlert */ class WebDriverAlertTest extends WebDriverTestCase { diff --git a/tests/functional/WebDriverByTest.php b/tests/functional/WebDriverByTest.php index 028db7920..4ff114751 100644 --- a/tests/functional/WebDriverByTest.php +++ b/tests/functional/WebDriverByTest.php @@ -24,7 +24,7 @@ class WebDriverByTest extends WebDriverTestCase { /** - * @dataProvider textElementsProvider + * @dataProvider provideTextElements * @param string $webDriverByLocatorMethod * @param string $webDriverByLocatorValue * @param string $expectedText @@ -52,7 +52,10 @@ public function testShouldFindTextElementByLocator( } } - public function textElementsProvider() + /** + * @return array[] + */ + public function provideTextElements() { return [ 'id' => ['id', 'id_test', 'Test by ID'], diff --git a/tests/functional/WebDriverCheckboxesTest.php b/tests/functional/WebDriverCheckboxesTest.php index 91513bd94..0ddcccd0d 100644 --- a/tests/functional/WebDriverCheckboxesTest.php +++ b/tests/functional/WebDriverCheckboxesTest.php @@ -18,8 +18,8 @@ use Facebook\WebDriver\Exception\NoSuchElementException; /** - * @covers \Facebook\WebDriver\WebDriverCheckboxes * @covers \Facebook\WebDriver\AbstractWebDriverCheckboxOrRadio + * @covers \Facebook\WebDriver\WebDriverCheckboxes * @group exclude-edge */ class WebDriverCheckboxesTest extends WebDriverTestCase @@ -137,7 +137,7 @@ public function testSelectByIndexInvalid() } /** - * @dataProvider selectByVisibleTextDataProvider + * @dataProvider provideSelectByVisibleTextData * * @param string $text * @param string $value @@ -154,9 +154,9 @@ public function testSelectByVisibleText($text, $value) } /** - * @return array + * @return array[] */ - public function selectByVisibleTextDataProvider() + public function provideSelectByVisibleTextData() { return [ ['J 2 B', 'j2b'], @@ -165,7 +165,7 @@ public function selectByVisibleTextDataProvider() } /** - * @dataProvider selectByVisiblePartialTextDataProvider + * @dataProvider provideSelectByVisiblePartialTextData * * @param string $text * @param string $value @@ -182,9 +182,9 @@ public function testSelectByVisiblePartialText($text, $value) } /** - * @return array + * @return array[] */ - public function selectByVisiblePartialTextDataProvider() + public function provideSelectByVisiblePartialTextData() { return [ ['2 B', 'j2b'], diff --git a/tests/functional/WebDriverNavigationTest.php b/tests/functional/WebDriverNavigationTest.php index d3aaebcb6..c2286f3b2 100644 --- a/tests/functional/WebDriverNavigationTest.php +++ b/tests/functional/WebDriverNavigationTest.php @@ -21,8 +21,8 @@ class WebDriverNavigationTest extends WebDriverTestCase { /** - * @covers ::to * @covers ::__construct + * @covers ::to */ public function testShouldNavigateToUrl() { diff --git a/tests/functional/WebDriverRadiosTest.php b/tests/functional/WebDriverRadiosTest.php index cf7b8378c..bb0eaa41e 100644 --- a/tests/functional/WebDriverRadiosTest.php +++ b/tests/functional/WebDriverRadiosTest.php @@ -19,8 +19,8 @@ use Facebook\WebDriver\Exception\UnsupportedOperationException; /** - * @covers \Facebook\WebDriver\WebDriverRadios * @covers \Facebook\WebDriver\AbstractWebDriverCheckboxOrRadio + * @covers \Facebook\WebDriver\WebDriverRadios * @group exclude-edge */ class WebDriverRadiosTest extends WebDriverTestCase @@ -115,7 +115,7 @@ public function testSelectByIndexInvalid() } /** - * @dataProvider selectByVisibleTextDataProvider + * @dataProvider provideSelectByVisibleTextData * * @param string $text * @param string $value @@ -128,9 +128,9 @@ public function testSelectByVisibleText($text, $value) } /** - * @return array + * @return array[] */ - public function selectByVisibleTextDataProvider() + public function provideSelectByVisibleTextData() { return [ ['J 3 B', 'j3b'], @@ -139,7 +139,7 @@ public function selectByVisibleTextDataProvider() } /** - * @dataProvider selectByVisiblePartialTextDataProvider + * @dataProvider provideSelectByVisiblePartialTextData * * @param string $text * @param string $value @@ -152,9 +152,9 @@ public function testSelectByVisiblePartialText($text, $value) } /** - * @return array + * @return array[] */ - public function selectByVisiblePartialTextDataProvider() + public function provideSelectByVisiblePartialTextData() { return [ ['3 B', 'j3b'], diff --git a/tests/functional/WebDriverSelectTest.php b/tests/functional/WebDriverSelectTest.php index b25dd03af..8d96a1944 100644 --- a/tests/functional/WebDriverSelectTest.php +++ b/tests/functional/WebDriverSelectTest.php @@ -21,8 +21,8 @@ /** * @group exclude-saucelabs - * @covers \Facebook\WebDriver\WebDriverSelect * @covers \Facebook\WebDriver\Exception\UnexpectedTagNameException + * @covers \Facebook\WebDriver\WebDriverSelect */ class WebDriverSelectTest extends WebDriverTestCase { @@ -58,7 +58,7 @@ public function testShouldThrowExceptionWhenNotInstantiatedOnSelectElement() } /** - * @dataProvider selectSelectorProvider + * @dataProvider provideSelectSelector * @param string $selector */ public function testShouldGetOptionsOfSelect($selector) @@ -72,7 +72,10 @@ public function testShouldGetOptionsOfSelect($selector) $this->assertCount(5, $options); } - public function selectSelectorProvider() + /** + * @return array[] + */ + public function provideSelectSelector() { return [ 'simple + +
    +