From 4bfeba1bac70c9c8b408306dd1027e9013394f32 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 11 Jan 2025 15:42:33 +0200 Subject: [PATCH 1/9] Inform developers about non-working "rightClick" on Selenium Server 3.x --- src/Selenium2Driver.php | 20 +++++++++++++++++++- tests/Selenium2Config.php | 12 ++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Selenium2Driver.php b/src/Selenium2Driver.php index fe8b1650..4e63c1a3 100755 --- a/src/Selenium2Driver.php +++ b/src/Selenium2Driver.php @@ -68,6 +68,11 @@ class Selenium2Driver extends CoreDriver */ private $isW3C = false; + /** + * @var bool + */ + private $isRightClickSupported = false; + /** * The timeout configuration * @var array{script?: int, implicit?: int, page?: int} @@ -352,7 +357,11 @@ public function start() $this->wdSession = $this->webDriver->session($this->browserName, $this->desiredCapabilities); $status = $this->webDriver->status(); - $this->isW3C = version_compare($status['build']['version'], '3.0.0', '>='); + list($majorSeleniumServerVersion) = explode('.', $status['build']['version']); + $this->isW3C = (int)$majorSeleniumServerVersion >= 3; + + // See: https://github.com/SeleniumHQ/selenium/commit/085ceed1f55fbaaa1d419b19c73264415c394905. + $this->isRightClickSupported = (int)$majorSeleniumServerVersion !== 3; $this->applyTimeouts(); $this->initialWindowHandle = $this->getWebDriverSession()->window_handle(); @@ -936,6 +945,15 @@ public function doubleClick(string $xpath) public function rightClick(string $xpath) { + if (!$this->isRightClickSupported) { + throw new DriverException(<<mouseOver($xpath); $this->getWebDriverSession()->click(array('button' => 2)); } diff --git a/tests/Selenium2Config.php b/tests/Selenium2Config.php index cc2d8347..bdc75c0c 100644 --- a/tests/Selenium2Config.php +++ b/tests/Selenium2Config.php @@ -7,6 +7,8 @@ use Behat\Mink\Tests\Driver\Basic\BasicAuthTest; use Behat\Mink\Tests\Driver\Basic\HeaderTest; use Behat\Mink\Tests\Driver\Basic\StatusCodeTest; +use Behat\Mink\Tests\Driver\Css\HoverTest; +use Behat\Mink\Tests\Driver\Js\EventsTest; use Behat\Mink\Tests\Driver\Js\JavascriptTest; class Selenium2Config extends AbstractConfig @@ -72,6 +74,16 @@ public function skipMessage($testCase, $test): ?string } } + if (array(HoverTest::class, 'testRightClickHover') === array($testCase, $test) + || array(EventsTest::class, 'testRightClick') === array($testCase, $test) + ) { + list($majorSeleniumServerVersion) = explode('.', $_SERVER['SELENIUM_VERSION'] ?? '0.0.0'); + + if ((int)$majorSeleniumServerVersion === 3) { + return 'The Selenium Server 3.x doesn\'t support right-clicking via JsonWireProtocol. See https://github.com/SeleniumHQ/selenium/commit/085ceed1f55fbaaa1d419b19c73264415c394905.'; + } + } + return parent::skipMessage($testCase, $test); } From b493d5b6c88fe3d843947988c06829a58ce58ab8 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 11 Jan 2025 16:21:58 +0200 Subject: [PATCH 2/9] Adjustments according to the review comments --- src/Selenium2Driver.php | 13 ++++++------- tests/Selenium2Config.php | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Selenium2Driver.php b/src/Selenium2Driver.php index 4e63c1a3..368cd1c2 100755 --- a/src/Selenium2Driver.php +++ b/src/Selenium2Driver.php @@ -357,11 +357,9 @@ public function start() $this->wdSession = $this->webDriver->session($this->browserName, $this->desiredCapabilities); $status = $this->webDriver->status(); - list($majorSeleniumServerVersion) = explode('.', $status['build']['version']); - $this->isW3C = (int)$majorSeleniumServerVersion >= 3; - - // See: https://github.com/SeleniumHQ/selenium/commit/085ceed1f55fbaaa1d419b19c73264415c394905. - $this->isRightClickSupported = (int)$majorSeleniumServerVersion !== 3; + $majorSeleniumServerVersion = (int)explode('.', $status['build']['version'])[0]; + $this->isW3C = $majorSeleniumServerVersion >= 3; + $this->isRightClickSupported = $majorSeleniumServerVersion !== 3; $this->applyTimeouts(); $this->initialWindowHandle = $this->getWebDriverSession()->window_handle(); @@ -946,10 +944,11 @@ public function doubleClick(string $xpath) public function rightClick(string $xpath) { if (!$this->isRightClickSupported) { + // See: https://github.com/SeleniumHQ/selenium/commit/085ceed1f55fbaaa1d419b19c73264415c394905. throw new DriverException(<< Date: Sat, 11 Jan 2025 21:20:59 +0200 Subject: [PATCH 3/9] Block driver usage above Selenium Server 3.x --- src/Selenium2Driver.php | 27 +++++++++++++++------------ tests/Selenium2Config.php | 6 +++++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/Selenium2Driver.php b/src/Selenium2Driver.php index 368cd1c2..ca53d83d 100755 --- a/src/Selenium2Driver.php +++ b/src/Selenium2Driver.php @@ -68,11 +68,6 @@ class Selenium2Driver extends CoreDriver */ private $isW3C = false; - /** - * @var bool - */ - private $isRightClickSupported = false; - /** * The timeout configuration * @var array{script?: int, implicit?: int, page?: int} @@ -354,12 +349,20 @@ private function executeJsOnElement(Element $element, string $script, bool $sync public function start() { try { - $this->wdSession = $this->webDriver->session($this->browserName, $this->desiredCapabilities); - $status = $this->webDriver->status(); $majorSeleniumServerVersion = (int)explode('.', $status['build']['version'])[0]; - $this->isW3C = $majorSeleniumServerVersion >= 3; - $this->isRightClickSupported = $majorSeleniumServerVersion !== 3; + + if ($majorSeleniumServerVersion > 3) { + throw new \Exception(<<isW3C = $majorSeleniumServerVersion === 3; + $this->wdSession = $this->webDriver->session($this->browserName, $this->desiredCapabilities); $this->applyTimeouts(); $this->initialWindowHandle = $this->getWebDriverSession()->window_handle(); @@ -943,12 +946,12 @@ public function doubleClick(string $xpath) public function rightClick(string $xpath) { - if (!$this->isRightClickSupported) { + if ($this->isW3C) { // See: https://github.com/SeleniumHQ/selenium/commit/085ceed1f55fbaaa1d419b19c73264415c394905. throw new DriverException(<< Date: Tue, 14 Jan 2025 12:53:34 +0200 Subject: [PATCH 4/9] Clarify, that Selenium Server 4 isn't supported --- .github/workflows/tests.yml | 3 +++ src/Selenium2Driver.php | 21 ++++++++++++------- tests/Custom/SeleniumSupportTest.php | 22 ++++++++++++++++++++ tests/Selenium2Config.php | 31 ++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 tests/Custom/SeleniumSupportTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7c44fe01..84be7104 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -52,6 +52,9 @@ jobs: - selenium_version: '3.141.59' php: '8.3' with_coverage: true + - selenium_version: '4' + php: '8.3' + with_coverage: true fail-fast: false steps: diff --git a/src/Selenium2Driver.php b/src/Selenium2Driver.php index ca53d83d..01e86c27 100755 --- a/src/Selenium2Driver.php +++ b/src/Selenium2Driver.php @@ -350,24 +350,29 @@ public function start() { try { $status = $this->webDriver->status(); - $majorSeleniumServerVersion = (int)explode('.', $status['build']['version'])[0]; + $seleniumVersion = $status['build']['version'] ?? $status['nodes'][0]['version'] ?? 'unknown'; + $seleniumMajorVersion = (int) explode('.', $seleniumVersion)[0]; + } catch (\Throwable $ex) { + throw new DriverException("Selenium Server version could not be detected: {$ex->getMessage()}", 0, $ex); + } - if ($majorSeleniumServerVersion > 3) { - throw new \Exception(<< 3) { + throw new DriverException(<<isW3C = $majorSeleniumServerVersion === 3; + try { + $this->isW3C = $seleniumMajorVersion === 3; $this->wdSession = $this->webDriver->session($this->browserName, $this->desiredCapabilities); $this->applyTimeouts(); $this->initialWindowHandle = $this->getWebDriverSession()->window_handle(); } catch (\Exception $e) { - throw new DriverException('Could not open connection: '.$e->getMessage(), 0, $e); + throw new DriverException('Could not open connection: ' . $e->getMessage(), 0, $e); } $this->started = true; diff --git a/tests/Custom/SeleniumSupportTest.php b/tests/Custom/SeleniumSupportTest.php new file mode 100644 index 00000000..307e8879 --- /dev/null +++ b/tests/Custom/SeleniumSupportTest.php @@ -0,0 +1,22 @@ +isSeleniumVersionSupported()) { + $this->markTestSkipped('This test applies to unsupported Selenium versions only.'); + } + + $this->expectException(DriverException::class); + $this->expectExceptionMessage('This driver requires Selenium version 3 or lower'); + + $this->createDriver()->start(); + } +} diff --git a/tests/Selenium2Config.php b/tests/Selenium2Config.php index 29bc488d..77beafe7 100644 --- a/tests/Selenium2Config.php +++ b/tests/Selenium2Config.php @@ -8,11 +8,23 @@ use Behat\Mink\Tests\Driver\Basic\HeaderTest; use Behat\Mink\Tests\Driver\Basic\StatusCodeTest; use Behat\Mink\Tests\Driver\Css\HoverTest; +use Behat\Mink\Tests\Driver\Custom\SeleniumSupportTest; use Behat\Mink\Tests\Driver\Js\EventsTest; use Behat\Mink\Tests\Driver\Js\JavascriptTest; class Selenium2Config extends AbstractConfig { + + /** + * @var integer + */ + protected $seleniumMajorVersion; + + public function __construct() + { + $this->seleniumMajorVersion = (int) explode('.', $_SERVER['SELENIUM_VERSION'] ?? '')[0]; + } + public static function getInstance(): self { return new self(); @@ -38,6 +50,8 @@ public function mapRemoteFilePath($file): string public function skipMessage($testCase, $test): ?string { + $testCallback = [$testCase, $test]; + if ( 'Behat\Mink\Tests\Driver\Form\Html5Test' === $testCase && 'testHtml5Types' === $test @@ -88,6 +102,13 @@ public function skipMessage($testCase, $test): ?string } } + // Skips all tests, exception mentioned below for an unsupported Selenium version. + if ([SeleniumSupportTest::class, 'testDriverCannotBeUsedInUnsupportedSelenium'] !== $testCallback + && !$this->isSeleniumVersionSupported() + ) { + return 'Does not apply to unsupported Selenium versions.'; + } + return parent::skipMessage($testCase, $test); } @@ -95,4 +116,14 @@ protected function supportsCss(): bool { return true; } + + public function isSeleniumVersionSupported(): bool + { + return $this->getSeleniumMajorVersion() < 4; + } + + protected function getSeleniumMajorVersion(): int + { + return $this->seleniumMajorVersion; + } } From adff281f8bbaea2f13030253ca6e69c05dac620d Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 14 Jan 2025 13:40:24 +0200 Subject: [PATCH 5/9] Confirm, that an exception is thrown when right-clicking in unsupported Selenium/browser --- tests/Custom/SeleniumSupportTest.php | 12 +++++++++ tests/Selenium2Config.php | 39 ++++++++++++++-------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/tests/Custom/SeleniumSupportTest.php b/tests/Custom/SeleniumSupportTest.php index 307e8879..deb86a94 100644 --- a/tests/Custom/SeleniumSupportTest.php +++ b/tests/Custom/SeleniumSupportTest.php @@ -19,4 +19,16 @@ public function testDriverCannotBeUsedInUnsupportedSelenium(): void $this->createDriver()->start(); } + + public function testThatRightClickingCannotBeUsedInUnsupportedSelenium(): void + { + if (Selenium2Config::getInstance()->isRightClickingInSeleniumSupported()) { + $this->markTestSkipped('This test applies to Selenium 3 only.'); + } + + $this->expectException(DriverException::class); + $this->expectExceptionMessage('This driver requires Selenium version 3 or lower'); + + $this->createDriver()->rightClick('//'); + } } diff --git a/tests/Selenium2Config.php b/tests/Selenium2Config.php index 77beafe7..e569700a 100644 --- a/tests/Selenium2Config.php +++ b/tests/Selenium2Config.php @@ -9,6 +9,7 @@ use Behat\Mink\Tests\Driver\Basic\StatusCodeTest; use Behat\Mink\Tests\Driver\Css\HoverTest; use Behat\Mink\Tests\Driver\Custom\SeleniumSupportTest; +use Behat\Mink\Tests\Driver\Form\Html5Test; use Behat\Mink\Tests\Driver\Js\EventsTest; use Behat\Mink\Tests\Driver\Js\JavascriptTest; @@ -52,15 +53,15 @@ public function skipMessage($testCase, $test): ?string { $testCallback = [$testCase, $test]; - if ( - 'Behat\Mink\Tests\Driver\Form\Html5Test' === $testCase - && 'testHtml5Types' === $test - ) { - return 'WebDriver does not support setting value in color inputs. See https://code.google.com/p/selenium/issues/detail?id=7650'; + if ([Html5Test::class, 'testHtml5Types'] === $testCallback) { + return <<getSeleniumMajorVersion() === 2) { + return 'The Firefox browser compatible with Selenium 2.x does not fully implement drag-n-drop support.'; } } - if (array(HoverTest::class, 'testRightClickHover') === array($testCase, $test) - || array(EventsTest::class, 'testRightClick') === array($testCase, $test) + if (([HoverTest::class, 'testRightClickHover'] === $testCallback || [EventsTest::class, 'testRightClick'] === $testCallback) + && $this->isRightClickingInSeleniumSupported() ) { - $majorSeleniumServerVersion = (int)explode('.', $_SERVER['SELENIUM_VERSION'] ?? '0.0.0')[0]; - - if ($majorSeleniumServerVersion === 3) { - return <<getSeleniumMajorVersion() < 3; + } + public function isSeleniumVersionSupported(): bool { return $this->getSeleniumMajorVersion() < 4; From c0ddf8391943cd87e97b67fde1c7f3c7e66323a4 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 14 Jan 2025 13:47:48 +0200 Subject: [PATCH 6/9] Corrected right click test skipping logic. --- tests/Selenium2Config.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Selenium2Config.php b/tests/Selenium2Config.php index e569700a..b62275df 100644 --- a/tests/Selenium2Config.php +++ b/tests/Selenium2Config.php @@ -88,8 +88,9 @@ public function skipMessage($testCase, $test): ?string } } + // Skip right-clicking tests, when an unsupported Selenium version detected. if (([HoverTest::class, 'testRightClickHover'] === $testCallback || [EventsTest::class, 'testRightClick'] === $testCallback) - && $this->isRightClickingInSeleniumSupported() + && !$this->isRightClickingInSeleniumSupported() ) { return << Date: Tue, 14 Jan 2025 13:47:57 +0200 Subject: [PATCH 7/9] Rephrased a comment --- tests/Selenium2Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Selenium2Config.php b/tests/Selenium2Config.php index b62275df..38b7f1bc 100644 --- a/tests/Selenium2Config.php +++ b/tests/Selenium2Config.php @@ -99,7 +99,7 @@ public function skipMessage($testCase, $test): ?string TEXT; } - // Skips all tests, exception mentioned below for an unsupported Selenium version. + // Skips all tests, except mentioned below, for an unsupported Selenium version. if ([SeleniumSupportTest::class, 'testDriverCannotBeUsedInUnsupportedSelenium'] !== $testCallback && !$this->isSeleniumVersionSupported() ) { From 4c5da8e3c732c0c3078426cd7a279c9d685cdc11 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 14 Jan 2025 13:57:15 +0200 Subject: [PATCH 8/9] Correct the broken "testThatRightClickingCannotBeUsedInUnsupportedSelenium" test --- tests/Custom/SeleniumSupportTest.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/Custom/SeleniumSupportTest.php b/tests/Custom/SeleniumSupportTest.php index deb86a94..f2cbb355 100644 --- a/tests/Custom/SeleniumSupportTest.php +++ b/tests/Custom/SeleniumSupportTest.php @@ -27,8 +27,15 @@ public function testThatRightClickingCannotBeUsedInUnsupportedSelenium(): void } $this->expectException(DriverException::class); - $this->expectExceptionMessage('This driver requires Selenium version 3 or lower'); + $this->expectExceptionMessage(<<createDriver()->rightClick('//'); + $driver = $this->createDriver(); + $driver->start(); + $driver->rightClick('//'); } } From 3145d7e373ef43e906f70d1017c4d8604b3adbaa Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 18 Jan 2025 14:07:18 +0200 Subject: [PATCH 9/9] Added test for unsupported "WebDriver::status" handling --- tests/Custom/WebDriverTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/Custom/WebDriverTest.php b/tests/Custom/WebDriverTest.php index a6f71e6d..3863f4d2 100644 --- a/tests/Custom/WebDriverTest.php +++ b/tests/Custom/WebDriverTest.php @@ -3,7 +3,9 @@ namespace Behat\Mink\Tests\Driver\Custom; use Behat\Mink\Driver\Selenium2Driver; +use Behat\Mink\Exception\DriverException; use Behat\Mink\Tests\Driver\TestCase; +use WebDriver\WebDriver; class WebDriverTest extends TestCase { @@ -18,4 +20,21 @@ public function testGetWebDriverSessionId() $driver = new Selenium2Driver(); $this->assertNull($driver->getWebDriverSessionId(), 'Not started session don\'t have an ID'); } + + public function testUnsupportedStatusResponseHandling(): void + { + $mockWebDriver = $this->createMock(WebDriver::class); + $mockWebDriver->expects($this->once()) + ->method('__call') + ->with($this->equalTo('status')) + ->willThrowException(new \RuntimeException('some internal error')); + + $driver = new Selenium2Driver(); + $driver->setWebDriver($mockWebDriver); + + $this->expectException(DriverException::class); + $this->expectExceptionMessage('Selenium Server version could not be detected: some internal error'); + + $driver->start(); + } }