From 6b551c314873c7c4a0950ca9cb3c51c27635ee3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 24 Aug 2021 12:11:32 +0200
Subject: [PATCH 001/130] Update codestyle, remove php-cs-fixer deprecations
---
.php_cs.dist => .php-cs-fixer.dist.php | 68 +++++++++++++------
lib/AbstractWebDriverCheckboxOrRadio.php | 2 +-
lib/Net/URLChecker.php | 1 +
lib/Remote/HttpCommandExecutor.php | 2 +-
lib/Remote/RemoteMouse.php | 2 +-
lib/Remote/RemoteWebDriver.php | 4 +-
lib/Remote/RemoteWebElement.php | 3 +-
lib/Remote/Service/DriverCommandExecutor.php | 2 +-
lib/Remote/Service/DriverService.php | 2 +-
lib/Support/Events/EventFiringWebDriver.php | 2 +
.../Events/EventFiringWebDriverNavigation.php | 2 +
lib/Support/Events/EventFiringWebElement.php | 3 +
lib/WebDriverExpectedCondition.php | 1 +
lib/WebDriverWait.php | 2 +-
lib/WebDriverWindow.php | 2 +-
.../Chrome/ChromeDevToolsDriverTest.php | 2 +-
.../Firefox/FirefoxDriverServiceTest.php | 4 +-
tests/functional/RemoteKeyboardTest.php | 2 +-
tests/functional/RemoteWebElementTest.php | 2 +
tests/functional/WebDriverActionsTest.php | 2 +-
tests/functional/WebDriverTestCase.php | 6 +-
tests/functional/WebDriverWindowTest.php | 6 +-
tests/functional/web/slow_pixel.png.php | 3 +-
tests/unit/Firefox/FirefoxOptionsTest.php | 2 +-
24 files changed, 82 insertions(+), 45 deletions(-)
rename .php_cs.dist => .php-cs-fixer.dist.php (58%)
diff --git a/.php_cs.dist b/.php-cs-fixer.dist.php
similarity index 58%
rename from .php_cs.dist
rename to .php-cs-fixer.dist.php
index a438f2095..5ffcc38ed 100644
--- a/.php_cs.dist
+++ b/.php-cs-fixer.dist.php
@@ -3,23 +3,34 @@
$finder = PhpCsFixer\Finder::create()
->in([__DIR__ . '/lib', __DIR__ . '/tests']);
-return PhpCsFixer\Config::create()
+return (new PhpCsFixer\Config())
->setRules([
'@PSR2' => true,
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => true,
- 'blank_line_before_return' => true,
+ 'blank_line_before_statement' => ['statements' => ['return', 'try']],
+ 'braces' => ['allow_single_line_anonymous_class_with_empty_body' => true, 'allow_single_line_closure' => true],
'cast_spaces' => true,
+ 'class_attributes_separation' => ['elements' => ['method' => 'one']],
+ 'clean_namespace' => true,
+ 'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
+ 'declare_equal_normalize' => true,
+ 'fopen_flag_order' => true,
+ 'fopen_flags' => true,
+ 'full_opening_tag' => true,
'function_typehint_space' => true,
- 'general_phpdoc_annotation_remove' => ['author'],
'implode_call' => true,
'is_null' => true,
+ 'lambda_not_used_import' => true,
'linebreak_after_opening_tag' => true,
'lowercase_cast' => true,
+ 'lowercase_static_reference' => true,
+ 'magic_constant_casing' => true,
+ 'magic_method_casing' => true,
'mb_str_functions' => true,
- 'method_separation' => true,
'native_function_casing' => true,
+ 'native_function_type_declaration_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
@@ -27,17 +38,23 @@
'no_empty_comment' => 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',
+ 'normalize_index_brace' => true,
+ 'no_extra_blank_lines' => [
+ 'tokens' => [
+ 'break',
+ 'case',
+ 'continue',
+ 'curly_brace_block',
+ 'default',
+ 'extra',
+ 'parenthesis_brace_block',
+ 'return',
+ 'square_brace_block',
+ 'switch',
+ 'throw',
+ 'use',
+ 'use_trait',
+ ],
],
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
@@ -47,6 +64,7 @@
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
+ 'no_useless_sprintf' => true,
'no_whitespace_in_blank_line' => true,
'object_operator_without_whitespace' => true,
'ordered_class_elements' => true,
@@ -55,11 +73,10 @@
'php_unit_dedicate_assert' => false,
'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_mock' => 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,
@@ -67,25 +84,34 @@
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
+ 'phpdoc_order_by_value' => ['annotations' => ['covers', 'group', 'throws']],
'phpdoc_order' => true,
+ 'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
- 'psr4' => true,
+ 'phpdoc_var_annotation_correct_order' => true,
+ 'psr_autoloading' => true,
'self_accessor' => true,
+ 'set_type_to_cast' => true,
'short_scalar_cast' => true,
'single_blank_line_before_namespace' => true,
'single_quote' => true,
+ 'single_space_after_construct' => true,
+ 'single_trait_insert_per_statement' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
+ 'strict_param' => true,
+ 'switch_continue_to_break' => true,
'ternary_operator_spaces' => true,
- 'trailing_comma_in_multiline_array' => true,
+ 'ternary_to_elvis_operator' => true,
+ 'trailing_comma_in_multiline' => ['elements' => ['arrays']],
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
- 'visibility_required' => true,
+ 'visibility_required' => ['elements' => ['method', 'property']],
'whitespace_after_comma_in_array' => true,
- 'yoda_style' => false,
+ 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false],
])
->setRiskyAllowed(true)
->setFinder($finder);
diff --git a/lib/AbstractWebDriverCheckboxOrRadio.php b/lib/AbstractWebDriverCheckboxOrRadio.php
index 9cd04c967..450bc387e 100644
--- a/lib/AbstractWebDriverCheckboxOrRadio.php
+++ b/lib/AbstractWebDriverCheckboxOrRadio.php
@@ -66,7 +66,7 @@ public function getFirstSelectedOption()
}
throw new NoSuchElementException(
- sprintf('No %s are selected', 'radio' === $this->type ? 'radio buttons' : 'checkboxes')
+ sprintf('No %s are selected', $this->type === 'radio' ? 'radio buttons' : 'checkboxes')
);
}
diff --git a/lib/Net/URLChecker.php b/lib/Net/URLChecker.php
index a4ff2df00..05e9cf1f6 100644
--- a/lib/Net/URLChecker.php
+++ b/lib/Net/URLChecker.php
@@ -59,6 +59,7 @@ private function getHTTPResponseCode($url)
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS);
$code = null;
+
try {
curl_exec($ch);
$info = curl_getinfo($ch);
diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php
index 69790e0e1..ea625c3c6 100644
--- a/lib/Remote/HttpCommandExecutor.php
+++ b/lib/Remote/HttpCommandExecutor.php
@@ -296,7 +296,7 @@ public function execute(WebDriverCommand $command)
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method);
}
- if (in_array($http_method, ['POST', 'PUT'])) {
+ if (in_array($http_method, ['POST', 'PUT'], true)) {
// 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, array_merge(static::DEFAULT_HTTP_HEADERS, ['Expect:']));
diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php
index 3495ea745..d2429967e 100644
--- a/lib/Remote/RemoteMouse.php
+++ b/lib/Remote/RemoteMouse.php
@@ -116,7 +116,7 @@ public function doubleClick(WebDriverCoordinates $where = null)
{
if ($this->isW3cCompliant) {
$clickActions = $this->createClickActions();
- $moveAction = null === $where ? [] : [$this->createMoveAction($where)];
+ $moveAction = $where === null ? [] : [$this->createMoveAction($where)];
$this->executor->execute(DriverCommand::ACTIONS, [
'actions' => [
[
diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php
index 215b7fd21..cb162265d 100644
--- a/lib/Remote/RemoteWebDriver.php
+++ b/lib/Remote/RemoteWebDriver.php
@@ -368,9 +368,7 @@ public function executeAsyncScript($script, array $arguments = [])
*/
public function takeScreenshot($save_as = null)
{
- $screenshot = base64_decode(
- $this->execute(DriverCommand::SCREENSHOT)
- );
+ $screenshot = base64_decode($this->execute(DriverCommand::SCREENSHOT), true);
if ($save_as !== null) {
$directoryPath = dirname($save_as);
diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php
index 6dc379378..2554848a0 100644
--- a/lib/Remote/RemoteWebElement.php
+++ b/lib/Remote/RemoteWebElement.php
@@ -478,7 +478,8 @@ public function takeElementScreenshot($save_as = null)
$this->executor->execute(
DriverCommand::TAKE_ELEMENT_SCREENSHOT,
[':id' => $this->id]
- )
+ ),
+ true
);
if ($save_as !== null) {
diff --git a/lib/Remote/Service/DriverCommandExecutor.php b/lib/Remote/Service/DriverCommandExecutor.php
index 36dc2f751..d16ec943d 100644
--- a/lib/Remote/Service/DriverCommandExecutor.php
+++ b/lib/Remote/Service/DriverCommandExecutor.php
@@ -28,8 +28,8 @@ public function __construct(DriverService $service)
/**
* @param WebDriverCommand $command
*
- * @throws WebDriverException
* @throws \Exception
+ * @throws WebDriverException
* @return WebDriverResponse
*/
public function execute(WebDriverCommand $command)
diff --git a/lib/Remote/Service/DriverService.php b/lib/Remote/Service/DriverService.php
index 8b8914815..237ca46b9 100644
--- a/lib/Remote/Service/DriverService.php
+++ b/lib/Remote/Service/DriverService.php
@@ -167,7 +167,7 @@ private function createProcess()
{
// 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())
+ && mb_strpos('@deprecated', (new \ReflectionClass(ProcessBuilder::class))->getDocComment()) === false
) {
$processBuilder = (new ProcessBuilder())
->setPrefix($this->executable)
diff --git a/lib/Support/Events/EventFiringWebDriver.php b/lib/Support/Events/EventFiringWebDriver.php
index 81a27816b..a4a74e346 100644
--- a/lib/Support/Events/EventFiringWebDriver.php
+++ b/lib/Support/Events/EventFiringWebDriver.php
@@ -63,6 +63,7 @@ public function getWebDriver()
public function get($url)
{
$this->dispatch('beforeNavigateTo', $url, $this);
+
try {
$this->driver->get($url);
} catch (WebDriverException $exception) {
@@ -162,6 +163,7 @@ public function executeAsyncScript($script, array $arguments = [])
}
$this->dispatch('beforeScript', $script, $this);
+
try {
$result = $this->driver->executeAsyncScript($script, $arguments);
} catch (WebDriverException $exception) {
diff --git a/lib/Support/Events/EventFiringWebDriverNavigation.php b/lib/Support/Events/EventFiringWebDriverNavigation.php
index 59eab3fd7..5070076d8 100644
--- a/lib/Support/Events/EventFiringWebDriverNavigation.php
+++ b/lib/Support/Events/EventFiringWebDriverNavigation.php
@@ -49,6 +49,7 @@ public function back()
'beforeNavigateBack',
$this->getDispatcher()->getDefaultDriver()
);
+
try {
$this->navigator->back();
} catch (WebDriverException $exception) {
@@ -68,6 +69,7 @@ public function forward()
'beforeNavigateForward',
$this->getDispatcher()->getDefaultDriver()
);
+
try {
$this->navigator->forward();
} catch (WebDriverException $exception) {
diff --git a/lib/Support/Events/EventFiringWebElement.php b/lib/Support/Events/EventFiringWebElement.php
index 0e9271665..a2fe4bb97 100644
--- a/lib/Support/Events/EventFiringWebElement.php
+++ b/lib/Support/Events/EventFiringWebElement.php
@@ -56,6 +56,7 @@ public function getElement()
public function sendKeys($value)
{
$this->dispatch('beforeChangeValueOf', $this);
+
try {
$this->element->sendKeys($value);
} catch (WebDriverException $exception) {
@@ -74,6 +75,7 @@ public function sendKeys($value)
public function click()
{
$this->dispatch('beforeClickOn', $this);
+
try {
$this->element->click();
} catch (WebDriverException $exception) {
@@ -129,6 +131,7 @@ public function findElements(WebDriverBy $by)
$this,
$this->dispatcher->getDefaultDriver()
);
+
try {
$elements = [];
foreach ($this->element->findElements($by) as $element) {
diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php
index 02d2e71e0..26914a161 100644
--- a/lib/WebDriverExpectedCondition.php
+++ b/lib/WebDriverExpectedCondition.php
@@ -422,6 +422,7 @@ function (WebDriver $driver) use ($visibility_of_element_located) {
$visibility_of_element_located->getApply(),
$driver
);
+
try {
if ($element !== null && $element->isEnabled()) {
return $element;
diff --git a/lib/WebDriverWait.php b/lib/WebDriverWait.php
index 34dd057ae..5b2009b3c 100644
--- a/lib/WebDriverWait.php
+++ b/lib/WebDriverWait.php
@@ -38,9 +38,9 @@ public function __construct(WebDriver $driver, $timeout_in_second = null, $inter
* @param callable|WebDriverExpectedCondition $func_or_ec
* @param string $message
*
+ * @throws \Exception
* @throws NoSuchElementException
* @throws TimeoutException
- * @throws \Exception
* @return mixed The return value of $func_or_ec
*/
public function until($func_or_ec, $message = '')
diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php
index e212f92ed..57754eb76 100644
--- a/lib/WebDriverWindow.php
+++ b/lib/WebDriverWindow.php
@@ -175,7 +175,7 @@ public function getScreenOrientation()
public function setScreenOrientation($orientation)
{
$orientation = mb_strtoupper($orientation);
- if (!in_array($orientation, ['PORTRAIT', 'LANDSCAPE'])) {
+ if (!in_array($orientation, ['PORTRAIT', 'LANDSCAPE'], true)) {
throw new IndexOutOfBoundsException(
'Orientation must be either PORTRAIT, or LANDSCAPE'
);
diff --git a/tests/functional/Chrome/ChromeDevToolsDriverTest.php b/tests/functional/Chrome/ChromeDevToolsDriverTest.php
index acbedb806..b927c73d6 100644
--- a/tests/functional/Chrome/ChromeDevToolsDriverTest.php
+++ b/tests/functional/Chrome/ChromeDevToolsDriverTest.php
@@ -6,10 +6,10 @@
use Facebook\WebDriver\WebDriverTestCase;
/**
- * @group exclude-saucelabs
* @group exclude-edge
* @group exclude-firefox
* @group exclude-safari
+ * @group exclude-saucelabs
*/
class ChromeDevToolsDriverTest extends WebDriverTestCase
{
diff --git a/tests/functional/Firefox/FirefoxDriverServiceTest.php b/tests/functional/Firefox/FirefoxDriverServiceTest.php
index e39259e2b..ce110acb7 100644
--- a/tests/functional/Firefox/FirefoxDriverServiceTest.php
+++ b/tests/functional/Firefox/FirefoxDriverServiceTest.php
@@ -6,10 +6,10 @@
use PHPUnit\Framework\TestCase;
/**
- * @group exclude-saucelabs
- * @group exclude-edge
* @group exclude-chrome
+ * @group exclude-edge
* @group exclude-safari
+ * @group exclude-saucelabs
* @covers \Facebook\WebDriver\Firefox\FirefoxDriverService
*/
class FirefoxDriverServiceTest extends TestCase
diff --git a/tests/functional/RemoteKeyboardTest.php b/tests/functional/RemoteKeyboardTest.php
index 947c8b6f9..a97b3343d 100644
--- a/tests/functional/RemoteKeyboardTest.php
+++ b/tests/functional/RemoteKeyboardTest.php
@@ -10,12 +10,12 @@ class RemoteKeyboardTest extends WebDriverTestCase
use RetrieveEventsTrait;
/**
+ * @group exclude-edge
* @group exclude-firefox
* Firefox does not properly support keyboard actions:
* https://github.com/mozilla/geckodriver/issues/245
* https://github.com/mozilla/geckodriver/issues/646
* https://github.com/mozilla/geckodriver/issues/944
- * @group exclude-edge
* @group exclude-safari
* https://feedbackassistant.apple.com/feedback/9051272
*/
diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php
index f10c7487b..20a9a3882 100644
--- a/tests/functional/RemoteWebElementTest.php
+++ b/tests/functional/RemoteWebElementTest.php
@@ -193,6 +193,7 @@ public function testGeckoDriverShouldClickNotInteractable()
$this->driver->get($this->getTestPageUrl('gecko653.html'));
$linkElement = $this->driver->findElement(WebDriverBy::id('a-index-plain-hidden'));
+
try {
$linkElement->click();
$this->fail('No exception was thrown when clicking an inaccessible link');
@@ -201,6 +202,7 @@ public function testGeckoDriverShouldClickNotInteractable()
}
$linkElement = $this->driver->findElement(WebDriverBy::id('a-index-hidden-block-child'));
+
try {
$linkElement->click();
$this->fail('No exception was thrown when clicking an inaccessible link');
diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php
index 91336c473..8a01fb998 100644
--- a/tests/functional/WebDriverActionsTest.php
+++ b/tests/functional/WebDriverActionsTest.php
@@ -184,9 +184,9 @@ public function testShouldMoveByOffset()
}
/**
- * @group exclude-saucelabs
* @group exclude-safari
* https://developer.apple.com/forums/thread/662677
+ * @group exclude-saucelabs
*/
public function testShouldDragAndDrop()
{
diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php
index 74c4d41e9..dbd6606ac 100644
--- a/tests/functional/WebDriverTestCase.php
+++ b/tests/functional/WebDriverTestCase.php
@@ -133,10 +133,10 @@ public static function skipForJsonWireProtocol($message = 'Not supported by Json
public static function skipForUnmatchedBrowsers($browsers = [], $message = null)
{
$browserName = (string) getenv('BROWSER_NAME');
- if (array_search($browserName, $browsers) === false) {
+ if (!in_array($browserName, $browsers, true)) {
if (!$message) {
- $browserlist = implode(', ', $browsers);
- $message = 'Browser ' . $browserName . ' not supported for this test (' . $browserlist . ')';
+ $browserList = implode(', ', $browsers);
+ $message = 'Browser ' . $browserName . ' not supported for this test (' . $browserList . ')';
}
static::markTestSkipped($message);
diff --git a/tests/functional/WebDriverWindowTest.php b/tests/functional/WebDriverWindowTest.php
index 3b100d8f7..3cd91e587 100644
--- a/tests/functional/WebDriverWindowTest.php
+++ b/tests/functional/WebDriverWindowTest.php
@@ -49,8 +49,8 @@ public function testShouldMaximizeWindow()
}
/**
- * @group exclude-saucelabs
* @group exclude-edge
+ * @group exclude-saucelabs
*/
public function testShouldFullscreenWindow()
{
@@ -74,10 +74,10 @@ public function testShouldFullscreenWindow()
}
/**
- * @group exclude-saucelabs
+ * @see https://bugs.chromium.org/p/chromium/issues/detail?id=1038050
* @group exclude-chrome
* @group exclude-safari
- * @see https://bugs.chromium.org/p/chromium/issues/detail?id=1038050
+ * @group exclude-saucelabs
*/
public function testShouldMinimizeWindow()
{
diff --git a/tests/functional/web/slow_pixel.png.php b/tests/functional/web/slow_pixel.png.php
index d95805e21..a834089ad 100644
--- a/tests/functional/web/slow_pixel.png.php
+++ b/tests/functional/web/slow_pixel.png.php
@@ -6,5 +6,6 @@
header('Content-Type: image/png');
echo base64_decode(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjY'
- . 'AAAAAIAAeIhvDMAAAAASUVORK5CYII='
+ . 'AAAAAIAAeIhvDMAAAAASUVORK5CYII=',
+ true
);
diff --git a/tests/unit/Firefox/FirefoxOptionsTest.php b/tests/unit/Firefox/FirefoxOptionsTest.php
index cd6948167..332f55de9 100644
--- a/tests/unit/Firefox/FirefoxOptionsTest.php
+++ b/tests/unit/Firefox/FirefoxOptionsTest.php
@@ -6,7 +6,7 @@
class FirefoxOptionsTest extends TestCase
{
- /** @var [] */
+ /** @var array */
const EXPECTED_DEFAULT_PREFS = [
FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED => false,
FirefoxPreferences::DEVTOOLS_JSONVIEW => false,
From b0d446169e7b3638cfb162b7101144bd793102c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 24 Aug 2021 12:44:06 +0200
Subject: [PATCH 002/130] Move php-cs-fixer to separate composer.json
---
.gitattributes | 1 +
.gitignore | 2 ++
composer.json | 11 ++++++++---
tools/php-cs-fixer/composer.json | 5 +++++
4 files changed, 16 insertions(+), 3 deletions(-)
create mode 100644 tools/php-cs-fixer/composer.json
diff --git a/.gitattributes b/.gitattributes
index 47a5c0fdf..e6146bc76 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,6 +2,7 @@
/scripts export-ignore
/tests export-ignore
+/tools export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/example.php export-ignore
diff --git a/.gitignore b/.gitignore
index d5605367c..697c5cce5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,9 @@
composer.phar
composer.lock
vendor
+tools/php-cs-fixer/vendor
.php_cs.cache
+.php-cs-fixer.cache
.phpunit.result.cache
phpunit.xml
logs/
diff --git a/composer.json b/composer.json
index d5d3f22f5..03f038316 100644
--- a/composer.json
+++ b/composer.json
@@ -23,7 +23,6 @@
"facebook/webdriver": "*"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.0",
"ondram/ci-detector": "^2.1 || ^3.5 || ^4.0",
"php-coveralls/php-coveralls": "^2.4",
"php-mock/php-mock-phpunit": "^1.1 || ^2.0",
@@ -59,6 +58,12 @@
},
"minimum-stability": "beta",
"scripts": {
+ "post-install-cmd": [
+ "php -r 'if (PHP_VERSION_ID > 70103) { exit(1); }' || composer install --working-dir=tools/php-cs-fixer --no-progress --no-interaction"
+ ],
+ "post-update-cmd": [
+ "php -r 'if (PHP_VERSION_ID > 70103) { exit(1); }' || composer update --working-dir=tools/php-cs-fixer --no-progress --no-interaction"
+ ],
"all": [
"@lint",
"@analyze",
@@ -66,12 +71,12 @@
],
"analyze": [
"vendor/bin/phpstan analyze -c phpstan.neon --ansi",
- "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff --dry-run -vvv --ansi",
+ "tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --diff --dry-run -vvv --ansi",
"vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/"
],
"fix": [
"@composer normalize",
- "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff -vvv || exit 0",
+ "tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --diff -vvv || exit 0",
"vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/"
],
"lint": [
diff --git a/tools/php-cs-fixer/composer.json b/tools/php-cs-fixer/composer.json
new file mode 100644
index 000000000..029b32c27
--- /dev/null
+++ b/tools/php-cs-fixer/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "friendsofphp/php-cs-fixer": "^3.0"
+ }
+}
From 108ee3c487d351b3f4606f2b5c147efd0b4bcd6e Mon Sep 17 00:00:00 2001
From: William Desportes
Date: Wed, 25 Aug 2021 22:11:04 +0200
Subject: [PATCH 003/130] Disable sauce labs tests on forks (#917)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Disable sauce labs tests on forks
Source: https://github.com/phpmyadmin/phpmyadmin/commit/8021847847714a6546b6af20579b82ab98da59e5
Co-authored-by: Ondřej Machulda
---
.github/workflows/sauce-labs.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/sauce-labs.yaml b/.github/workflows/sauce-labs.yaml
index e183bdfac..427afc6fd 100644
--- a/.github/workflows/sauce-labs.yaml
+++ b/.github/workflows/sauce-labs.yaml
@@ -8,6 +8,8 @@ on:
jobs:
tests:
runs-on: ubuntu-latest
+ # Source: https://github.community/t/do-not-run-cron-workflows-in-forks/17636/2
+ if: (github.event_name == 'schedule' && github.repository == 'php-webdriver/php-webdriver') || (github.event_name != 'schedule')
env:
SAUCELABS: 1
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
From 429d6615750580cf764d478019f1534531216a1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Mon, 23 Aug 2021 13:53:12 +0200
Subject: [PATCH 004/130] Allow Symfony 6
---
CHANGELOG.md | 2 ++
composer.json | 6 +++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 085f24450..a765afa00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
This project versioning adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
+### Changed
+- Allow installation of Symfony 6 components.
## 1.11.1 - 2021-05-21
### Fixed
diff --git a/composer.json b/composer.json
index 03f038316..9eb616cf2 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
"ext-json": "*",
"ext-zip": "*",
"symfony/polyfill-mbstring": "^1.12",
- "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0"
+ "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0 || ^6.0"
},
"replace": {
"facebook/webdriver": "*"
@@ -29,7 +29,7 @@
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9",
"squizlabs/php_codesniffer": "^3.5",
- "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0"
+ "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0 || ^6.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
@@ -56,7 +56,7 @@
"tests/functional/"
]
},
- "minimum-stability": "beta",
+ "minimum-stability": "dev",
"scripts": {
"post-install-cmd": [
"php -r 'if (PHP_VERSION_ID > 70103) { exit(1); }' || composer install --working-dir=tools/php-cs-fixer --no-progress --no-interaction"
From d4bb05460fa247295b69b401c5ab87892805fd04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Thu, 26 Aug 2021 14:07:34 +0200
Subject: [PATCH 005/130] Add getDomProperty method to read IDL properties of
elements (fixes #929)
---
CHANGELOG.md | 3 +++
lib/Remote/RemoteWebElement.php | 25 +++++++++++++++++++++++
lib/WebDriverElement.php | 15 +++++++++++++-
tests/functional/RemoteWebElementTest.php | 25 ++++++++++++++++++++++-
tests/functional/web/index.html | 7 ++++++-
5 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a765afa00..6e62cdcf0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
This project versioning adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
+### Added
+- `RemoteWebElement::getDomProperty()` method to read JavaScript properties of an element (like the value of `innerHTML` etc.) in W3C mode.
+
### Changed
- Allow installation of Symfony 6 components.
diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php
index 2554848a0..216044279 100644
--- a/lib/Remote/RemoteWebElement.php
+++ b/lib/Remote/RemoteWebElement.php
@@ -3,6 +3,7 @@
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\Exception\ElementNotInteractableException;
+use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\Internal\WebDriverLocatable;
@@ -132,6 +133,8 @@ public function findElements(WebDriverBy $by)
/**
* Get the value of the given attribute of the element.
+ * Attribute is meant what is declared in the HTML markup of the element.
+ * To read a value of a IDL "JavaScript" property (like `innerHTML`), use `getDomProperty()` method.
*
* @param string $attribute_name The name of the attribute.
* @return string|null The value of the attribute.
@@ -162,6 +165,28 @@ public function getAttribute($attribute_name)
return $this->executor->execute(DriverCommand::GET_ELEMENT_ATTRIBUTE, $params);
}
+ /**
+ * Gets the value of a IDL JavaScript property of this element (for example `innerHTML`, `tagName` etc.).
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Glossary/IDL
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element#properties
+ * @param string $propertyName
+ * @return string|null The property's current value or null if the value is not set or the property does not exist.
+ */
+ public function getDomProperty($propertyName)
+ {
+ if (!$this->isW3cCompliant) {
+ throw new UnsupportedOperationException('This method is only supported in W3C mode');
+ }
+
+ $params = [
+ ':name' => $propertyName,
+ ':id' => $this->id,
+ ];
+
+ return $this->executor->execute(DriverCommand::GET_ELEMENT_PROPERTY, $params);
+ }
+
/**
* Get the value of a given CSS property.
*
diff --git a/lib/WebDriverElement.php b/lib/WebDriverElement.php
index 538e0a8e5..3409dde18 100644
--- a/lib/WebDriverElement.php
+++ b/lib/WebDriverElement.php
@@ -22,13 +22,26 @@ public function clear();
public function click();
/**
- * Get the value of a the given attribute of the element.
+ * Get the value of the given attribute of the element.
+ * Attribute is meant what is declared in the HTML markup of the element.
+ * To read a value of a IDL "JavaScript" property (like `innerHTML`), use `getDomProperty()` method.
*
* @param string $attribute_name The name of the attribute.
* @return string|null The value of the attribute.
*/
public function getAttribute($attribute_name);
+ /*
+ * Gets the value of a IDL JavaScript property of this element (for example `innerHTML`, `tagName` etc.).
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Glossary/IDL
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element#properties
+ * @param string $propertyName
+ * @return string|null The property's current value or null if the value is not set or the property does not exist.
+ * @todo Add in next major release (BC)
+ */
+ // public function getDomProperty($propertyName);
+
/**
* Get the value of a given CSS property.
*
diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php
index 20a9a3882..086e905ae 100644
--- a/tests/functional/RemoteWebElementTest.php
+++ b/tests/functional/RemoteWebElementTest.php
@@ -42,6 +42,29 @@ public function testShouldGetAttributeValue()
$this->assertSame('note', $element->getAttribute('role'));
$this->assertSame('height: 5em; border: 1px solid black;', $element->getAttribute('style'));
$this->assertSame('text-simple', $element->getAttribute('id'));
+ $this->assertNull($element->getAttribute('notExisting'));
+ }
+
+ /**
+ * @covers ::getDomProperty
+ */
+ public function testShouldGetDomPropertyValue()
+ {
+ self::skipForJsonWireProtocol();
+
+ $this->driver->get($this->getTestPageUrl('index.html'));
+
+ $element = $this->driver->findElement(WebDriverBy::id('div-with-html'));
+
+ $this->assertStringContainsString(
+ '
This div has some more html inside.
',
+ $element->getDomProperty('innerHTML')
+ );
+ $this->assertSame('foo bar', $element->getDomProperty('className')); // IDL property
+ $this->assertSame('foo bar', $element->getAttribute('class')); // HTML attribute should be the same
+ $this->assertSame('DIV', $element->getDomProperty('tagName'));
+ $this->assertSame(2, $element->getDomProperty('childElementCount'));
+ $this->assertNull($element->getDomProperty('notExistingProperty'));
}
/**
@@ -56,7 +79,7 @@ public function testShouldGetLocation()
$elementLocation = $element->getLocation();
$this->assertInstanceOf(WebDriverPoint::class, $elementLocation);
$this->assertSame(33, $elementLocation->getX());
- $this->assertSame(500, $elementLocation->getY());
+ $this->assertSame(550, $elementLocation->getY());
}
/**
diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html
index 6107856ed..f94c7bc53 100644
--- a/tests/functional/web/index.html
+++ b/tests/functional/web/index.html
@@ -60,7 +60,12 @@
Welcome to the php-webdriver testing page.
stripped
-
+
+
This div has some more html inside.
+
+
+
+
Foo
From 94db34ff5a1b1519ee8427b54002134b4232cb21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Mon, 11 Oct 2021 13:47:19 +0200
Subject: [PATCH 006/130] Do not use unsafe static when accessing private
propery
---
lib/Remote/DesiredCapabilities.php | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php
index 5b726406d..a7bde312e 100644
--- a/lib/Remote/DesiredCapabilities.php
+++ b/lib/Remote/DesiredCapabilities.php
@@ -30,7 +30,7 @@ public function __construct(array $capabilities = [])
public static function createFromW3cCapabilities(array $capabilities = [])
{
- $w3cToOss = array_flip(static::$ossToW3c);
+ $w3cToOss = array_flip(self::$ossToW3c);
foreach ($w3cToOss as $w3cCapability => $ossCapability) {
// Copy W3C capabilities to OSS ones
@@ -229,16 +229,16 @@ public function toW3cCompatibleArray()
}
// Convert capabilities with changed name
- if (array_key_exists($capabilityKey, static::$ossToW3c)) {
+ if (array_key_exists($capabilityKey, self::$ossToW3c)) {
if ($capabilityKey === WebDriverCapabilityType::PLATFORM) {
- $w3cCapabilities[static::$ossToW3c[$capabilityKey]] = mb_strtolower($capabilityValue);
+ $w3cCapabilities[self::$ossToW3c[$capabilityKey]] = mb_strtolower($capabilityValue);
// Remove platformName if it is set to "any"
- if ($w3cCapabilities[static::$ossToW3c[$capabilityKey]] === 'any') {
- unset($w3cCapabilities[static::$ossToW3c[$capabilityKey]]);
+ if ($w3cCapabilities[self::$ossToW3c[$capabilityKey]] === 'any') {
+ unset($w3cCapabilities[self::$ossToW3c[$capabilityKey]]);
}
} else {
- $w3cCapabilities[static::$ossToW3c[$capabilityKey]] = $capabilityValue;
+ $w3cCapabilities[self::$ossToW3c[$capabilityKey]] = $capabilityValue;
}
}
From 8ffa927b270e932449e8015abf4d38bb0eff24b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Mon, 11 Oct 2021 17:05:03 +0200
Subject: [PATCH 007/130] Add newSession constructor to create new session
command without typehint violation
---
CHANGELOG.md | 1 +
lib/Chrome/ChromeDriver.php | 9 ++-------
lib/Firefox/FirefoxDriver.php | 5 +----
lib/Remote/RemoteWebDriver.php | 6 +-----
lib/Remote/WebDriverCommand.php | 14 ++++++++++++--
tests/unit/Remote/WebDriverCommandTest.php | 9 +++++++++
6 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e62cdcf0..f36782390 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
### Added
- `RemoteWebElement::getDomProperty()` method to read JavaScript properties of an element (like the value of `innerHTML` etc.) in W3C mode.
+- `WebDriverCommand::newSession()` constructor to create new session command without violating typehints.
### Changed
- Allow installation of Symfony 6 components.
diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php
index a8feac7b8..1d840eaed 100644
--- a/lib/Chrome/ChromeDriver.php
+++ b/lib/Chrome/ChromeDriver.php
@@ -4,7 +4,6 @@
use Facebook\WebDriver\Local\LocalWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
-use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\Service\DriverCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;
@@ -48,9 +47,7 @@ public static function startUsingDriverService(
}
$executor = new DriverCommandExecutor($service);
- $newSessionCommand = new WebDriverCommand(
- null,
- DriverCommand::NEW_SESSION,
+ $newSessionCommand = WebDriverCommand::newSession(
[
'capabilities' => [
'firstMatch' => [(object) $capabilities->toW3cCompatibleArray()],
@@ -76,9 +73,7 @@ public static function startUsingDriverService(
*/
public function startSession(DesiredCapabilities $desired_capabilities)
{
- $command = new WebDriverCommand(
- null,
- DriverCommand::NEW_SESSION,
+ $command = WebDriverCommand::newSession(
[
'capabilities' => [
'firstMatch' => [(object) $desired_capabilities->toW3cCompatibleArray()],
diff --git a/lib/Firefox/FirefoxDriver.php b/lib/Firefox/FirefoxDriver.php
index 1d525da85..34dd13de2 100644
--- a/lib/Firefox/FirefoxDriver.php
+++ b/lib/Firefox/FirefoxDriver.php
@@ -4,7 +4,6 @@
use Facebook\WebDriver\Local\LocalWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
-use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\Service\DriverCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;
@@ -44,9 +43,7 @@ public static function startUsingDriverService(
}
$executor = new DriverCommandExecutor($service);
- $newSessionCommand = new WebDriverCommand(
- null,
- DriverCommand::NEW_SESSION,
+ $newSessionCommand = WebDriverCommand::newSession(
[
'capabilities' => [
'firstMatch' => [(object) $capabilities->toW3cCompatibleArray()],
diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php
index cb162265d..9bc3c7a89 100644
--- a/lib/Remote/RemoteWebDriver.php
+++ b/lib/Remote/RemoteWebDriver.php
@@ -126,11 +126,7 @@ public static function create(
$parameters['desiredCapabilities'] = (object) $desired_capabilities->toArray();
- $command = new WebDriverCommand(
- null,
- DriverCommand::NEW_SESSION,
- $parameters
- );
+ $command = WebDriverCommand::newSession($parameters);
$response = $executor->execute($command);
diff --git a/lib/Remote/WebDriverCommand.php b/lib/Remote/WebDriverCommand.php
index e21fbdaae..27f21b605 100644
--- a/lib/Remote/WebDriverCommand.php
+++ b/lib/Remote/WebDriverCommand.php
@@ -4,7 +4,7 @@
class WebDriverCommand
{
- /** @var string */
+ /** @var string|null */
protected $sessionID;
/** @var string */
protected $name;
@@ -16,6 +16,7 @@ class WebDriverCommand
* @param string $name Constant from DriverCommand
* @param array $parameters
* @todo In 2.0 force parameters to be an array, then remove is_array() checks in HttpCommandExecutor
+ * @todo In 2.0 make constructor private. Use by default static `::create()` with sessionID type string.
*/
public function __construct($session_id, $name, $parameters)
{
@@ -24,6 +25,15 @@ public function __construct($session_id, $name, $parameters)
$this->parameters = $parameters;
}
+ /**
+ * @return self
+ */
+ public static function newSession(array $parameters)
+ {
+ // TODO: In 2.0 call empty constructor and assign properties directly.
+ return new self(null, DriverCommand::NEW_SESSION, $parameters);
+ }
+
/**
* @return string
*/
@@ -33,7 +43,7 @@ public function getName()
}
/**
- * @return string
+ * @return string|null Could be null for newSession command
*/
public function getSessionID()
{
diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php
index 0bf6efb20..8ba7abf33 100644
--- a/tests/unit/Remote/WebDriverCommandTest.php
+++ b/tests/unit/Remote/WebDriverCommandTest.php
@@ -14,4 +14,13 @@ public function testShouldSetOptionsUsingConstructor()
$this->assertSame('bar-baz-name', $command->getName());
$this->assertSame(['foo' => 'bar'], $command->getParameters());
}
+
+ public function testShouldCreateNewSessionCommand()
+ {
+ $command = WebDriverCommand::newSession(['bar' => 'baz']);
+
+ $this->assertNull($command->getSessionID());
+ $this->assertSame('newSession', $command->getName());
+ $this->assertSame(['bar' => 'baz'], $command->getParameters());
+ }
}
From e55e6ab0dc42a48a98b04e5229d319482c6a9908 Mon Sep 17 00:00:00 2001
From: Kyle
Date: Thu, 14 Oct 2021 11:28:08 +0200
Subject: [PATCH 008/130] Fix PHP 8.1 compatibility (#935)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Fix PHP 8.1 compatibility
Co-authored-by: Ondřej Machulda
---
lib/Chrome/ChromeOptions.php | 2 ++
lib/Firefox/FirefoxOptions.php | 3 +++
lib/Remote/HttpCommandExecutor.php | 3 ++-
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/lib/Chrome/ChromeOptions.php b/lib/Chrome/ChromeOptions.php
index 6599197b6..7c81955d8 100644
--- a/lib/Chrome/ChromeOptions.php
+++ b/lib/Chrome/ChromeOptions.php
@@ -4,6 +4,7 @@
use Facebook\WebDriver\Remote\DesiredCapabilities;
use JsonSerializable;
+use ReturnTypeWillChange;
/**
* The class manages the capabilities in ChromeDriver.
@@ -43,6 +44,7 @@ class ChromeOptions implements JsonSerializable
*
* @return array
*/
+ #[ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->toArray();
diff --git a/lib/Firefox/FirefoxOptions.php b/lib/Firefox/FirefoxOptions.php
index fc16fdb75..06e61c3d5 100644
--- a/lib/Firefox/FirefoxOptions.php
+++ b/lib/Firefox/FirefoxOptions.php
@@ -2,6 +2,8 @@
namespace Facebook\WebDriver\Firefox;
+use ReturnTypeWillChange;
+
/**
* Class to manage Firefox-specific capabilities
*
@@ -101,6 +103,7 @@ public function toArray()
return $array;
}
+ #[ReturnTypeWillChange]
public function jsonSerialize()
{
return new \ArrayObject($this->toArray());
diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php
index ea625c3c6..2d510a038 100644
--- a/lib/Remote/HttpCommandExecutor.php
+++ b/lib/Remote/HttpCommandExecutor.php
@@ -268,7 +268,8 @@ public function execute(WebDriverCommand $command)
$http_method = $http_options['method'];
$url = $http_options['url'];
- $url = str_replace(':sessionId', $command->getSessionID(), $url);
+ $sessionID = $command->getSessionID();
+ $url = str_replace(':sessionId', $sessionID === null ? '' : $sessionID, $url);
$params = $command->getParameters();
foreach ($params as $name => $value) {
if ($name[0] === ':') {
From 0769f3cacbd0de57dc6c27c2d8167d04502bfecb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Thu, 14 Oct 2021 11:29:23 +0200
Subject: [PATCH 009/130] Update changelog
---
CHANGELOG.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f36782390..4254aeb41 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/).
### Changed
- Allow installation of Symfony 6 components.
+### Fixed
+- PHP 8.1 compatibility.
+
## 1.11.1 - 2021-05-21
### Fixed
- `RemoteWebElement::getLocationOnScreenOnceScrolledIntoView()` was missing polyfill implementation for W3C mode and not working in eg. Safari.
From 99d4856ed7dffcdf6a52eccd6551e83d8d557ceb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Thu, 14 Oct 2021 11:30:02 +0200
Subject: [PATCH 010/130] Release version 1.12.0
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4254aeb41..0d66e7cf6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
# Changelog
This project versioning adheres to [Semantic Versioning](http://semver.org/).
-## Unreleased
+## 1.12.0 - 2021-10-14
### Added
- `RemoteWebElement::getDomProperty()` method to read JavaScript properties of an element (like the value of `innerHTML` etc.) in W3C mode.
- `WebDriverCommand::newSession()` constructor to create new session command without violating typehints.
From c16f8ee103da236d93d9bed406de49b424c064c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Mon, 8 Nov 2021 17:50:46 +0100
Subject: [PATCH 011/130] Fix phpdoc for getAttribute and getDomProperty to
match the specs
---
lib/Remote/RemoteWebElement.php | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php
index 216044279..9a4515083 100644
--- a/lib/Remote/RemoteWebElement.php
+++ b/lib/Remote/RemoteWebElement.php
@@ -137,7 +137,8 @@ public function findElements(WebDriverBy $by)
* To read a value of a IDL "JavaScript" property (like `innerHTML`), use `getDomProperty()` method.
*
* @param string $attribute_name The name of the attribute.
- * @return string|null The value of the attribute.
+ * @return string|true|null The value of the attribute. If this is boolean attribute, return true if the element
+ * has it, otherwise return null.
*/
public function getAttribute($attribute_name)
{
@@ -171,7 +172,7 @@ public function getAttribute($attribute_name)
* @see https://developer.mozilla.org/en-US/docs/Glossary/IDL
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element#properties
* @param string $propertyName
- * @return string|null The property's current value or null if the value is not set or the property does not exist.
+ * @return mixed|null The property's current value or null if the value is not set or the property does not exist.
*/
public function getDomProperty($propertyName)
{
From ac1b5fab5691f5231b49cabacf2528d91e94fd36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Sat, 11 Dec 2021 11:40:57 +0100
Subject: [PATCH 012/130] Normalize composer.json to new schema
---
composer.json | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/composer.json b/composer.json
index 9eb616cf2..2b72e5bad 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,8 @@
{
"name": "php-webdriver/webdriver",
- "type": "library",
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
+ "license": "MIT",
+ "type": "library",
"keywords": [
"webdriver",
"selenium",
@@ -10,7 +11,6 @@
"chromedriver"
],
"homepage": "https://github.com/php-webdriver/php-webdriver",
- "license": "MIT",
"require": {
"php": "^5.6 || ~7.0 || ^8.0",
"ext-curl": "*",
@@ -19,9 +19,6 @@
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0 || ^6.0"
},
- "replace": {
- "facebook/webdriver": "*"
- },
"require-dev": {
"ondram/ci-detector": "^2.1 || ^3.5 || ^4.0",
"php-coveralls/php-coveralls": "^2.4",
@@ -31,12 +28,13 @@
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0 || ^6.0"
},
+ "replace": {
+ "facebook/webdriver": "*"
+ },
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
},
- "config": {
- "sort-packages": true
- },
+ "minimum-stability": "dev",
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
@@ -56,7 +54,9 @@
"tests/functional/"
]
},
- "minimum-stability": "dev",
+ "config": {
+ "sort-packages": true
+ },
"scripts": {
"post-install-cmd": [
"php -r 'if (PHP_VERSION_ID > 70103) { exit(1); }' || composer install --working-dir=tools/php-cs-fixer --no-progress --no-interaction"
From 0d4bc565c6f03369ff8b54772a8be6beb8befbe6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Wed, 5 Jan 2022 13:28:31 +0100
Subject: [PATCH 013/130] Docs: Extend findElement(s) documentation to better
explain XPath behavior (#956)
---
lib/Remote/RemoteWebElement.php | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php
index 9a4515083..e0503698e 100644
--- a/lib/Remote/RemoteWebElement.php
+++ b/lib/Remote/RemoteWebElement.php
@@ -89,6 +89,10 @@ public function click()
/**
* Find the first WebDriverElement within this element using the given mechanism.
*
+ * When using xpath be aware that webdriver follows standard conventions: a search prefixed with "//" will
+ * search the entire document from the root, not just the children (relative context) of this current node.
+ * Use ".//" to limit your search to the children of this element.
+ *
* @param WebDriverBy $by
* @return RemoteWebElement NoSuchElementException is thrown in HttpCommandExecutor if no element is found.
* @see WebDriverBy
@@ -109,6 +113,10 @@ public function findElement(WebDriverBy $by)
/**
* Find all WebDriverElements within this element using the given mechanism.
*
+ * When using xpath be aware that webdriver follows standard conventions: a search prefixed with "//" will
+ * search the entire document from the root, not just the children (relative context) of this current node.
+ * Use ".//" to limit your search to the children of this element.
+ *
* @param WebDriverBy $by
* @return RemoteWebElement[] A list of all WebDriverElements, or an empty
* array if nothing matches
From 289d043ae62eed17cefa3292abd4da7cb938ba7a Mon Sep 17 00:00:00 2001
From: Johnny van de Laar
Date: Thu, 6 Jan 2022 11:02:33 +0100
Subject: [PATCH 014/130] Fix PHP 8.1 deprecations in the Cookie class
---
lib/Cookie.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/Cookie.php b/lib/Cookie.php
index 1005bd0dc..9570f5d6d 100644
--- a/lib/Cookie.php
+++ b/lib/Cookie.php
@@ -207,16 +207,19 @@ public function toArray()
return $cookie;
}
+ #[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->cookie[$offset]);
}
+ #[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->cookie[$offset] : null;
}
+ #[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if ($value === null) {
From 25ba0d63a99496095ecb6560b110fb330824e387 Mon Sep 17 00:00:00 2001
From: Johnny van de Laar
Date: Thu, 6 Jan 2022 11:13:17 +0100
Subject: [PATCH 015/130] Also offsetUnset
---
lib/Cookie.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/Cookie.php b/lib/Cookie.php
index 9570f5d6d..b02e0c58f 100644
--- a/lib/Cookie.php
+++ b/lib/Cookie.php
@@ -229,6 +229,7 @@ public function offsetSet($offset, $value)
}
}
+ #[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->cookie[$offset]);
From 3d84328de3d7c87edeaf3b5d8213b9c119675bef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 29 Mar 2022 15:59:29 +0200
Subject: [PATCH 016/130] Allow composer-normalize plugin
---
composer.json | 3 +++
1 file changed, 3 insertions(+)
diff --git a/composer.json b/composer.json
index 2b72e5bad..90f2d0f28 100644
--- a/composer.json
+++ b/composer.json
@@ -55,6 +55,9 @@
]
},
"config": {
+ "allow-plugins": {
+ "ergebnis/composer-normalize": true
+ },
"sort-packages": true
},
"scripts": {
From 20b831f76253f492bc5edd11babbdb4e282f0c05 Mon Sep 17 00:00:00 2001
From: tomsykes
Date: Wed, 12 Jan 2022 10:20:42 +0000
Subject: [PATCH 017/130] Add PHPDoc return types to ArrayAccess methods, to
suppress deprecation warnings in Symfony 5.4/PHP7.4
---
lib/Cookie.php | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/Cookie.php b/lib/Cookie.php
index b02e0c58f..1a31c7df8 100644
--- a/lib/Cookie.php
+++ b/lib/Cookie.php
@@ -207,18 +207,27 @@ public function toArray()
return $cookie;
}
+ /**
+ * @return bool
+ */
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->cookie[$offset]);
}
+ /**
+ * @return mixed
+ */
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->cookie[$offset] : null;
}
+ /**
+ * @return void
+ */
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
@@ -229,6 +238,9 @@ public function offsetSet($offset, $value)
}
}
+ /**
+ * @return void
+ */
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
From 301923820e757cc867c0bfc18e79f09e3c0cbb0f Mon Sep 17 00:00:00 2001
From: tomsykes
Date: Wed, 12 Jan 2022 10:32:28 +0000
Subject: [PATCH 018/130] Adding param annotations
Automated checks failed previously due to lack of param annotations
---
lib/Cookie.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lib/Cookie.php b/lib/Cookie.php
index 1a31c7df8..77b04687c 100644
--- a/lib/Cookie.php
+++ b/lib/Cookie.php
@@ -208,6 +208,7 @@ public function toArray()
}
/**
+ * @param mixed $offset
* @return bool
*/
#[\ReturnTypeWillChange]
@@ -217,6 +218,7 @@ public function offsetExists($offset)
}
/**
+ * @param mixed $offset
* @return mixed
*/
#[\ReturnTypeWillChange]
@@ -226,6 +228,8 @@ public function offsetGet($offset)
}
/**
+ * @param mixed $offset
+ * @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
@@ -239,6 +243,7 @@ public function offsetSet($offset, $value)
}
/**
+ * @param mixed $offset
* @return void
*/
#[\ReturnTypeWillChange]
From 1ddc140bd636080979cc28021d0a23fddcafba7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 29 Mar 2022 15:54:00 +0200
Subject: [PATCH 019/130] Disable phpdoc_no_empty_return fixer to allow forward
compatibility with PHP 8.1
---
.php-cs-fixer.dist.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 5ffcc38ed..051fb6579 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -82,7 +82,7 @@
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
- 'phpdoc_no_empty_return' => true,
+ // 'phpdoc_no_empty_return' => true, // disabled to allow forward compatibility with PHP 8.1
'phpdoc_no_package' => true,
'phpdoc_order_by_value' => ['annotations' => ['covers', 'group', 'throws']],
'phpdoc_order' => true,
From 6fb804b74e3ec74816be4d5111f0591824026205 Mon Sep 17 00:00:00 2001
From: William Desportes
Date: Fri, 16 Apr 2021 15:22:42 +0200
Subject: [PATCH 020/130] use Doctum to re-build API docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-Authored-By: Ondřej Machulda
---
.github/workflows/docs-lint.yml | 23 ++++++++++++++
.github/workflows/docs-publish.yml | 35 +++++++++++++++++++++
.gitignore | 1 +
scripts/docs-template.html | 7 +++++
scripts/doctum.php | 30 ++++++++++++++++++
scripts/update-built-docs.sh | 50 ++++++++++++++++++++++++++++++
6 files changed, 146 insertions(+)
create mode 100644 .github/workflows/docs-lint.yml
create mode 100755 .github/workflows/docs-publish.yml
create mode 100644 scripts/docs-template.html
create mode 100644 scripts/doctum.php
create mode 100755 scripts/update-built-docs.sh
diff --git a/.github/workflows/docs-lint.yml b/.github/workflows/docs-lint.yml
new file mode 100644
index 000000000..56667ce70
--- /dev/null
+++ b/.github/workflows/docs-lint.yml
@@ -0,0 +1,23 @@
+name: Lint PHP documentation
+
+on:
+ push:
+ pull_request:
+ branches:
+ - 'main'
+
+jobs:
+ lint-docs:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Lint PHP documentation
+ uses: sudo-bot/action-doctum@v5
+ with:
+ config-file: scripts/doctum.php
+ method: 'parse'
+ cli-args: '--output-format=github --no-ansi --no-progress -v --ignore-parse-errors'
diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml
new file mode 100755
index 000000000..35941e2dd
--- /dev/null
+++ b/.github/workflows/docs-publish.yml
@@ -0,0 +1,35 @@
+name: Publish API documentation
+
+on:
+ repository_dispatch:
+ types: [ run-build-api-docs ]
+ workflow_dispatch:
+ schedule:
+ - cron: "00 12 * * *"
+
+jobs:
+ publish-pages:
+ environment:
+ name: API documentation
+ url: https://php-webdriver.github.io/php-webdriver/
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ ssh-key: ${{ secrets.SSH_KEY_DEPLOY }}
+
+ - name: Build PHP documentation
+ uses: sudo-bot/action-doctum@v5
+ with:
+ config-file: scripts/doctum.php
+ method: 'update'
+ cli-args: '--output-format=github --no-ansi --no-progress -v --ignore-parse-errors'
+
+ - name: Set commit author
+ run: |
+ git config user.name "Automated"
+ git config user.email "actions@users.noreply.github.com"
+ - name: Push the changes
+ run: ./scripts/update-built-docs.sh
diff --git a/.gitignore b/.gitignore
index 697c5cce5..a9384110d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ tools/php-cs-fixer/vendor
.phpunit.result.cache
phpunit.xml
logs/
+build/
# generic files to ignore
*.lock
diff --git a/scripts/docs-template.html b/scripts/docs-template.html
new file mode 100644
index 000000000..4814f5ec5
--- /dev/null
+++ b/scripts/docs-template.html
@@ -0,0 +1,7 @@
+
+
+
+
+ Taking you to the latest documentation.
+
+
\ No newline at end of file
diff --git a/scripts/doctum.php b/scripts/doctum.php
new file mode 100644
index 000000000..9cb2cc784
--- /dev/null
+++ b/scripts/doctum.php
@@ -0,0 +1,30 @@
+files()
+ ->name('*.php')
+ ->in($srcRoot . 'lib');
+
+$versions = GitVersionCollection::create($srcRoot)
+ ->addFromTags('1.*') // only latest minor version
+ ->addFromTags('0.6.0')
+ ->add('main', 'main branch')
+;
+
+return new Doctum($iterator, [
+ 'title' => 'php-webdriver API',
+ 'theme' => 'default',
+ 'build_dir' => $root . '/build/dist/%version%/',
+ 'cache_dir' => $root . '/build/cache/%version%/',
+ 'include_parent_data' => true,
+ 'remote_repository' => new GitHubRemoteRepository('php-webdriver/php-webdriver', $srcRoot),
+ 'versions' => $versions,
+ 'base_url' => 'https://php-webdriver.github.io/php-webdriver/%version/'
+]);
diff --git a/scripts/update-built-docs.sh b/scripts/update-built-docs.sh
new file mode 100755
index 000000000..76646bed5
--- /dev/null
+++ b/scripts/update-built-docs.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+set -e
+
+cleanup() {
+ git ls-files ./ | xargs -r -n 1 rm
+ rm -rfd ./*
+}
+
+copyToTemp() {
+ TEMP_DIR="$(mktemp -d --suffix=_doctum-build-php-webdriver)"
+ cp -rp build/dist/* "${TEMP_DIR}"
+ cp ./scripts/docs-template.html "${TEMP_DIR}/index.html"
+}
+
+emptyAndRemoveTemp() {
+ mv "${TEMP_DIR}"/* ./
+ # Create symlink for main to latest
+ ln -s -r ./main ./latest
+ # Create symlink for main to master
+ ln -s -r ./main ./master
+ # Create symlink for main to community
+ ln -s -r ./main ./community
+ rm -rf "${TEMP_DIR}"
+}
+
+commitAndPushChanges() {
+ # Push the changes, only if there is changes
+ git add -A
+ git diff-index --quiet HEAD || git commit -m "Api documentations update ($(date --rfc-3339=seconds --utc))" -m "#apidocs" && if [ -z "${SKIP_PUSH}" ]; then git push; fi
+}
+
+if [ ! -d ./build/dist ]; then
+ echo 'Missing built docs'
+ exit 1
+fi
+
+# Remove cache dir, do not upload it
+rm -rf ./build/cache
+
+copyToTemp
+# Remove build dir, do not upload it
+rm -rf ./build
+
+git checkout gh-pages
+
+cleanup
+emptyAndRemoveTemp
+commitAndPushChanges
+
+git checkout - > /dev/null
From de0b3f0714a0a48f48b3c02c34e075dc27141105 Mon Sep 17 00:00:00 2001
From: William Desportes
Date: Mon, 2 May 2022 13:35:41 +0200
Subject: [PATCH 021/130] Bump actions/checkout to v3
---
.github/workflows/docs-publish.yml | 2 +-
.github/workflows/sauce-labs.yaml | 2 +-
.github/workflows/tests.yaml | 8 ++++----
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml
index 35941e2dd..02a50534b 100755
--- a/.github/workflows/docs-publish.yml
+++ b/.github/workflows/docs-publish.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
fetch-depth: 0
ssh-key: ${{ secrets.SSH_KEY_DEPLOY }}
diff --git a/.github/workflows/sauce-labs.yaml b/.github/workflows/sauce-labs.yaml
index 427afc6fd..878743ef1 100644
--- a/.github/workflows/sauce-labs.yaml
+++ b/.github/workflows/sauce-labs.yaml
@@ -26,7 +26,7 @@ jobs:
name: ${{ matrix.name }} (${{ matrix.tunnel-id }})
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 45e5761e9..ccf4bd0c0 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -11,7 +11,7 @@ jobs:
name: "Code style and static analysis"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
@@ -32,7 +32,7 @@ jobs:
name: "Markdown link check"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: gaurav-nelson/github-action-markdown-link-check@v1
with:
use-verbose-mode: 'yes'
@@ -50,7 +50,7 @@ jobs:
- { php-version: '8.1', dependencies: '--ignore-platform-req=php' }
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
@@ -101,7 +101,7 @@ jobs:
name: "Functional tests (${{ matrix.browser }}, Selenium server: ${{ matrix.selenium-server }}, W3C: ${{ matrix.w3c }})"
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
From f5d8821d33d0ff791fc4a238d1551ad830f97053 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Mon, 2 May 2022 14:18:32 +0200
Subject: [PATCH 022/130] Update changelog
---
CHANGELOG.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d66e7cf6..47445f7a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,16 @@
# Changelog
This project versioning adheres to [Semantic Versioning](http://semver.org/).
+## Unreleased
+### Fixed
+- Improper PHP documentation for `getAttribute()` and `getDomProperty()`.
+- Unsafe use of `static::` when accessing private property in `DesiredCapabilities`.
+- PHP 8.1 deprecations in the `Cookie` class.
+
+### Changed
+- Docs: Extend `findElement()`/`findElements()` method documentation to better explain XPath behavior.
+- Add `@return` and `@param` type annotations to Cookie class to avoid deprecations in PHP 8.1.
+
## 1.12.0 - 2021-10-14
### Added
- `RemoteWebElement::getDomProperty()` method to read JavaScript properties of an element (like the value of `innerHTML` etc.) in W3C mode.
From 3cca205d3d0d72eb0e191488fac76cfed99a17f4 Mon Sep 17 00:00:00 2001
From: William Desportes
Date: Tue, 3 May 2022 11:36:28 +0200
Subject: [PATCH 023/130] Fix #977 - broken open-search URL
---
scripts/doctum.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/doctum.php b/scripts/doctum.php
index 9cb2cc784..08e722917 100644
--- a/scripts/doctum.php
+++ b/scripts/doctum.php
@@ -24,7 +24,7 @@
'build_dir' => $root . '/build/dist/%version%/',
'cache_dir' => $root . '/build/cache/%version%/',
'include_parent_data' => true,
- 'remote_repository' => new GitHubRemoteRepository('php-webdriver/php-webdriver', $srcRoot),
+ 'remote_repository' => new GitHubRemoteRepository('php-webdriver/php-webdriver', $srcRoot),
'versions' => $versions,
- 'base_url' => 'https://php-webdriver.github.io/php-webdriver/%version/'
+ 'base_url' => 'https://php-webdriver.github.io/php-webdriver/%version%/'
]);
From b27ddf458d273c7d4602106fcaf978aa0b7fe15a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 3 May 2022 14:08:51 +0200
Subject: [PATCH 024/130] Release version 1.12.1
---
CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47445f7a7..f90ff9039 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
This project versioning adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
+
+## 1.12.1 - 2022-05-03
### Fixed
- Improper PHP documentation for `getAttribute()` and `getDomProperty()`.
- Unsafe use of `static::` when accessing private property in `DesiredCapabilities`.
From eed18d3ce1cce6c1833dacced516b43bef75e916 Mon Sep 17 00:00:00 2001
From: Nikhil <6836536+qwertynik@users.noreply.github.com>
Date: Tue, 28 Jun 2022 19:20:07 +0530
Subject: [PATCH 025/130] Removing link to deprecated site
The linked site for Chromedriver will soon be deprecated. Adding link to the latest site.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 689a497ab..2eb411645 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ This could be Selenium standalone server, but for local development, you can sen
📙 Below you will find a simple example. Make sure to read our wiki for [more information on Chrome/Chromedriver](https://github.com/php-webdriver/php-webdriver/wiki/Chrome).
-Install the latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads).
+Install the latest Chrome and [Chromedriver](https://sites.google.com/chromium.org/driver/downloads).
Make sure to have a compatible version of Chromedriver and Chrome!
Run `chromedriver` binary, you can pass `port` argument, so that it listens on port 4444:
From e31d1f792ec71e777de1bee71e1260df2108d078 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 23 Aug 2022 18:07:24 +0200
Subject: [PATCH 026/130] Replace no-response probot with
'lee-dohm/no-response' action
---
.github/no-response.yml | 17 -----------------
.github/workflows/no-response.yaml | 26 ++++++++++++++++++++++++++
2 files changed, 26 insertions(+), 17 deletions(-)
delete mode 100644 .github/no-response.yml
create mode 100644 .github/workflows/no-response.yaml
diff --git a/.github/no-response.yml b/.github/no-response.yml
deleted file mode 100644
index 320baf22f..000000000
--- a/.github/no-response.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# Configuration for probot-no-response - https://github.com/probot/no-response
-
-# Number of days of inactivity before an Issue is closed for lack of response
-daysUntilClose: 14
-
-# Label requiring a response
-responseRequiredLabel: "waiting for reaction"
-
-# Comment to post when closing an Issue for lack of response. Set to `false` to disable
-closeComment: >
- This issue has been automatically closed because there has been no response
- to our request for more information from the original author. With only the
- information that is currently in the issue, we don't have enough information
- to take action.
-
- If the original issue author adds comment with more information,
- this issue will be automatically reopened and we can investigate further.
diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml
new file mode 100644
index 000000000..2970c7d72
--- /dev/null
+++ b/.github/workflows/no-response.yaml
@@ -0,0 +1,26 @@
+name: No Response
+
+# Both `issue_comment` and `scheduled` event types are required for this Action to work properly.
+on:
+ issue_comment:
+ types: [created]
+ schedule:
+ - cron: '33 * * * *' # every hour at :33
+
+jobs:
+ noResponse:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: lee-dohm/no-response@v0.5.0
+ with:
+ token: ${{ github.token }}
+ daysUntilClose: 14
+ responseRequiredLabel: 'waiting for reaction'
+ closeComment: >
+ This issue has been automatically closed because there has been no response
+ to our request for more information from the original author. With only the
+ information that is currently in the issue, we don't have enough information
+ to take action.
+
+ If the original issue author adds comment with more information,
+ this issue will be automatically reopened and we can investigate further.
From 518a8822432a8440864c40154a5c5fd44a38e9a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Tue, 23 Aug 2022 13:28:31 +0200
Subject: [PATCH 027/130] Mark getAllSessions() deprecated in W3C WebDriver
---
lib/Remote/RemoteWebDriver.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php
index 9bc3c7a89..fc068a8f3 100644
--- a/lib/Remote/RemoteWebDriver.php
+++ b/lib/Remote/RemoteWebDriver.php
@@ -555,6 +555,7 @@ public function getCapabilities()
/**
* Returns a list of the currently active sessions.
*
+ * @deprecated Removed in W3C WebDriver.
* @param string $selenium_server_url The url of the remote Selenium WebDriver server
* @param int $timeout_in_ms
* @return array
From c51f35d9c6681e890a6d0a05b26cfc463bbc990c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Wed, 24 Aug 2022 17:11:09 +0200
Subject: [PATCH 028/130] Separate takeScreenshot logic to better handle
errors, DRY and to fix PHP 8.1 deprecations
---
CHANGELOG.md | 2 +
lib/Remote/RemoteWebDriver.php | 15 +--
lib/Remote/RemoteWebElement.php | 20 +---
lib/Support/ScreenshotHelper.php | 77 +++++++++++++++
tests/functional/RemoteWebDriverTest.php | 4 +-
tests/functional/RemoteWebElementTest.php | 2 +-
tests/unit/Support/ScreenshotHelperTest.php | 103 ++++++++++++++++++++
7 files changed, 190 insertions(+), 33 deletions(-)
create mode 100644 lib/Support/ScreenshotHelper.php
create mode 100644 tests/unit/Support/ScreenshotHelperTest.php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f90ff9039..71c0f3904 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
This project versioning adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
+### Changed
+- Handle errors when taking screenshots. `WebDriverException` is thrown if WebDriver returns empty or invalid screenshot data.
## 1.12.1 - 2022-05-03
### Fixed
diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php
index fc068a8f3..f45ae8da1 100644
--- a/lib/Remote/RemoteWebDriver.php
+++ b/lib/Remote/RemoteWebDriver.php
@@ -4,6 +4,7 @@
use Facebook\WebDriver\Interactions\WebDriverActions;
use Facebook\WebDriver\JavaScriptExecutor;
+use Facebook\WebDriver\Support\ScreenshotHelper;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverCapabilities;
@@ -364,19 +365,7 @@ public function executeAsyncScript($script, array $arguments = [])
*/
public function takeScreenshot($save_as = null)
{
- $screenshot = base64_decode($this->execute(DriverCommand::SCREENSHOT), true);
-
- if ($save_as !== null) {
- $directoryPath = dirname($save_as);
-
- if (!file_exists($directoryPath)) {
- mkdir($directoryPath, 0777, true);
- }
-
- file_put_contents($save_as, $screenshot);
- }
-
- return $screenshot;
+ return (new ScreenshotHelper($this->getExecuteMethod()))->takePageScreenshot($save_as);
}
/**
diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php
index e0503698e..add916934 100644
--- a/lib/Remote/RemoteWebElement.php
+++ b/lib/Remote/RemoteWebElement.php
@@ -7,6 +7,7 @@
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\Internal\WebDriverLocatable;
+use Facebook\WebDriver\Support\ScreenshotHelper;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverDimension;
use Facebook\WebDriver\WebDriverElement;
@@ -508,24 +509,7 @@ public function getID()
*/
public function takeElementScreenshot($save_as = null)
{
- $screenshot = base64_decode(
- $this->executor->execute(
- DriverCommand::TAKE_ELEMENT_SCREENSHOT,
- [':id' => $this->id]
- ),
- true
- );
-
- if ($save_as !== null) {
- $directoryPath = dirname($save_as);
- if (!file_exists($directoryPath)) {
- mkdir($directoryPath, 0777, true);
- }
-
- file_put_contents($save_as, $screenshot);
- }
-
- return $screenshot;
+ return (new ScreenshotHelper($this->executor))->takeElementScreenshot($this->id, $save_as);
}
/**
diff --git a/lib/Support/ScreenshotHelper.php b/lib/Support/ScreenshotHelper.php
new file mode 100644
index 000000000..5fe18efd1
--- /dev/null
+++ b/lib/Support/ScreenshotHelper.php
@@ -0,0 +1,77 @@
+executor = $executor;
+ }
+
+ /**
+ * @param string|null $saveAs
+ * @throws WebDriverException
+ * @return string
+ */
+ public function takePageScreenshot($saveAs = null)
+ {
+ $commandToExecute = [DriverCommand::SCREENSHOT];
+
+ return $this->takeScreenshot($commandToExecute, $saveAs);
+ }
+
+ public function takeElementScreenshot($elementId, $saveAs = null)
+ {
+ $commandToExecute = [DriverCommand::TAKE_ELEMENT_SCREENSHOT, [':id' => $elementId]];
+
+ return $this->takeScreenshot($commandToExecute, $saveAs);
+ }
+
+ private function takeScreenshot(array $commandToExecute, $saveAs = null)
+ {
+ $response = $this->executor->execute(...$commandToExecute);
+
+ if (!is_string($response)) {
+ throw new WebDriverException('Error taking screenshot, no data received from the remote end');
+ }
+
+ $screenshot = base64_decode($response, true);
+
+ if ($screenshot === false) {
+ throw new WebDriverException('Error decoding screenshot data');
+ }
+
+ if ($saveAs !== null) {
+ $this->saveScreenshotToPath($screenshot, $saveAs);
+ }
+
+ return $screenshot;
+ }
+
+ private function saveScreenshotToPath($screenshot, $path)
+ {
+ $this->createDirectoryIfNotExists(dirname($path));
+
+ file_put_contents($path, $screenshot);
+ }
+
+ private function createDirectoryIfNotExists($directoryPath)
+ {
+ if (!file_exists($directoryPath)) {
+ if (!mkdir($directoryPath, 0777, true) && !is_dir($directoryPath)) {
+ throw new WebDriverException(sprintf('Directory "%s" was not created', $directoryPath));
+ }
+ }
+ }
+}
diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php
index 25b01c40f..984c11978 100644
--- a/tests/functional/RemoteWebDriverTest.php
+++ b/tests/functional/RemoteWebDriverTest.php
@@ -250,6 +250,7 @@ public function testShouldExecuteScriptWithParamsAndReturnValue()
/**
* @covers ::takeScreenshot
+ * @covers \Facebook\WebDriver\Support\ScreenshotHelper
*/
public function testShouldTakeScreenshot()
{
@@ -269,6 +270,7 @@ public function testShouldTakeScreenshot()
/**
* @covers ::takeScreenshot
+ * @covers \Facebook\WebDriver\Support\ScreenshotHelper
* @group exclude-safari
* Safari is returning different color profile and it does not have way to configure "force-color-profile"
*/
@@ -277,7 +279,7 @@ public function testShouldSaveScreenshotToFile()
if (!extension_loaded('gd')) {
$this->markTestSkipped('GD extension must be enabled');
}
- // Intentionally save screenshot to subdirectory to tests it is being created
+
$screenshotPath = sys_get_temp_dir() . '/' . uniqid('php-webdriver-') . '/selenium-screenshot.png';
$this->driver->get($this->getTestPageUrl('index.html'));
diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php
index 086e905ae..bb6568f6d 100644
--- a/tests/functional/RemoteWebElementTest.php
+++ b/tests/functional/RemoteWebElementTest.php
@@ -455,6 +455,7 @@ public function testShouldFindMultipleChildElements()
/**
* @covers ::takeElementScreenshot
+ * @covers \Facebook\WebDriver\Support\ScreenshotHelper
* @group exclude-saucelabs
*/
public function testShouldTakeAndSaveElementScreenshot()
@@ -469,7 +470,6 @@ public function testShouldTakeAndSaveElementScreenshot()
$isCi = (new CiDetector())->isCiDetected();
$isSafari = getenv('BROWSER_NAME') === 'safari';
- // Intentionally save screenshot to subdirectory to tests it is being created
$screenshotPath = sys_get_temp_dir() . '/' . uniqid('php-webdriver-') . '/element-screenshot.png';
$this->driver->get($this->getTestPageUrl('index.html'));
diff --git a/tests/unit/Support/ScreenshotHelperTest.php b/tests/unit/Support/ScreenshotHelperTest.php
new file mode 100644
index 000000000..edc3f661f
--- /dev/null
+++ b/tests/unit/Support/ScreenshotHelperTest.php
@@ -0,0 +1,103 @@
+assertDirectoryNotExists($directoryPath);
+
+ $executorMock = $this->createMock(RemoteExecuteMethod::class);
+ $executorMock->expects($this->once())
+ ->method('execute')
+ ->with($this->equalTo(DriverCommand::SCREENSHOT))
+ ->willReturn(self::BLACK_PIXEL);
+
+ $helper = new ScreenshotHelper($executorMock);
+ $output = $helper->takePageScreenshot($fullFilePath);
+
+ $this->assertSame(base64_decode(self::BLACK_PIXEL, true), $output);
+
+ $this->assertDirectoryExists($directoryPath);
+ $this->assertFileExists($fullFilePath);
+
+ unlink($fullFilePath);
+ rmdir($directoryPath);
+ }
+
+ public function testShouldOnlyReturnBase64IfDirectoryNotProvided()
+ {
+ $executorMock = $this->createMock(RemoteExecuteMethod::class);
+ $executorMock->expects($this->once())
+ ->method('execute')
+ ->with($this->equalTo(DriverCommand::SCREENSHOT))
+ ->willReturn(self::BLACK_PIXEL);
+
+ $helper = new ScreenshotHelper($executorMock);
+ $output = $helper->takePageScreenshot();
+
+ $this->assertSame(base64_decode(self::BLACK_PIXEL, true), $output);
+ }
+
+ public function testShouldSaveElementScreenshotToSubdirectoryIfNotExists()
+ {
+ $fullFilePath = sys_get_temp_dir() . '/' . uniqid('php-webdriver-', true) . '/screenshot.png';
+ $directoryPath = dirname($fullFilePath);
+ $this->assertDirectoryNotExists($directoryPath);
+ $elementId = 'foo-id';
+
+ $executorMock = $this->createMock(RemoteExecuteMethod::class);
+ $executorMock->expects($this->once())
+ ->method('execute')
+ ->with(DriverCommand::TAKE_ELEMENT_SCREENSHOT, [':id' => $elementId])
+ ->willReturn(self::BLACK_PIXEL);
+
+ $helper = new ScreenshotHelper($executorMock);
+ $output = $helper->takeElementScreenshot($elementId, $fullFilePath);
+
+ $this->assertSame(base64_decode(self::BLACK_PIXEL, true), $output);
+ $this->assertDirectoryExists($directoryPath);
+ $this->assertFileExists($fullFilePath);
+
+ unlink($fullFilePath);
+ rmdir($directoryPath);
+ }
+
+ /**
+ * @dataProvider provideInvalidData
+ * @param mixed $data
+ * @param string $expectedExceptionMessage
+ */
+ public function testShouldThrowExceptionWhenInvalidDataReceived($data, $expectedExceptionMessage)
+ {
+ $executorMock = $this->createMock(RemoteExecuteMethod::class);
+ $executorMock->expects($this->once())
+ ->method('execute')
+ ->with($this->equalTo(DriverCommand::SCREENSHOT))
+ ->willReturn($data);
+
+ $helper = new ScreenshotHelper($executorMock);
+
+ $this->expectException(WebDriverException::class);
+ $this->expectExceptionMessage($expectedExceptionMessage);
+ $helper->takePageScreenshot();
+ }
+
+ public function provideInvalidData()
+ {
+ return [
+ 'empty response' => [null, 'Error taking screenshot, no data received from the remote end'],
+ 'not valid base64 response' => ['invalid%base64', 'Error decoding screenshot data'],
+ ];
+ }
+}
From 1dcffc8af811b9485c3df1c1e95577ae39ed2bb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Sat, 27 Aug 2022 10:37:11 +0200
Subject: [PATCH 029/130] Run functional tests on Selenium server 4.3
---
.github/workflows/tests.yaml | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index ccf4bd0c0..2cea57936 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -84,7 +84,7 @@ jobs:
functional-tests:
runs-on: ${{ matrix.os }}
env:
- SELENIUM_SERVER_DOWNLOAD_URL: http://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar
+ SELENIUM_SERVER_DOWNLOAD_URL: https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.3.0/selenium-server-4.3.0.jar
strategy:
fail-fast: false
@@ -116,13 +116,13 @@ jobs:
- name: Start Selenium standalone server
# If you want to run your Selenium WebDriver tests on GitHub actions, we recommend using service containers
# with eg. selenium/standalone-chrome image. See https://docs.github.com/en/actions/guides/about-service-containers
- # But for the purpose of testing this library itself, we need more control so we set everything up manually.
+ # But for the purpose of testing this library itself, we need more control, so we set everything up manually.
if: ${{ matrix.selenium-server }}
run: |
- mkdir -p build
- wget -q -t 3 -O build/selenium-server-standalone.jar $SELENIUM_SERVER_DOWNLOAD_URL
- java -jar build/selenium-server-standalone.jar -version
- xvfb-run --server-args="-screen 0, 1280x720x24" --auto-servernum java -jar build/selenium-server-standalone.jar -log logs/selenium-server.log &
+ mkdir -p build logs
+ wget -q -t 3 -O build/selenium-server.jar $SELENIUM_SERVER_DOWNLOAD_URL
+ java -jar build/selenium-server.jar standalone --version
+ xvfb-run --server-args="-screen 0, 1280x720x24" --auto-servernum java -jar build/selenium-server.jar standalone --log logs/selenium-server.log &
- name: Start ChromeDriver
if: ${{ !matrix.selenium-server && matrix.browser == 'chrome' }}
From 02a17b3843693cc1f994606aa0b7f8d8531ae540 Mon Sep 17 00:00:00 2001
From: Maxim Leontyev
Date: Thu, 16 Aug 2018 13:25:05 +0300
Subject: [PATCH 030/130] Add new firefox xpi extensions support
---
lib/Firefox/FirefoxProfile.php | 73 ++++++++-----
.../functional/Firefox/FirefoxProfileTest.php | 96 ++++++++++++++++++
.../FirefoxWebdriverTestExtension-0.1-fx.xpi | Bin 0 -> 5384 bytes
3 files changed, 143 insertions(+), 26 deletions(-)
create mode 100644 tests/functional/Firefox/FirefoxProfileTest.php
create mode 100644 tests/functional/Fixtures/FirefoxWebdriverTestExtension-0.1-fx.xpi
diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php
index cce9baaf4..645d5cae9 100644
--- a/lib/Firefox/FirefoxProfile.php
+++ b/lib/Firefox/FirefoxProfile.php
@@ -185,44 +185,65 @@ public function encode()
/**
* @param string $extension The path to the extension.
* @param string $profile_dir The path to the profile directory.
+ * @throws WebDriverException
+ * @throws \Exception
* @return string The path to the directory of this extension.
*/
private function installExtension($extension, $profile_dir)
{
- $temp_dir = $this->createTempDirectory('WebDriverFirefoxProfileExtension');
+ $temp_dir = $this->createTempDirectory();
+
$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 (mb_strpos($value, '//www.mozilla.org/2004/em-rdf') > 0) {
- if ($key != '') {
- $prefix = $key . ':'; // Separate the namespace from the name.
- }
- break;
- }
- }
+ $mozilla_rsa_path = $temp_dir . '/META-INF/mozilla.rsa';
+ $mozilla_rsa_binary_data = file_get_contents($mozilla_rsa_path);
+ $mozilla_rsa_hex = bin2hex($mozilla_rsa_binary_data);
+
+ //We need to find plugin id. This is second occurrence of object identifier "2.5.4.3 commonName"
+
+ //That is marker "2.5.4.3 commonName" in hex:
+ $object_identifier_hex_marker = '0603550403';
+
+ $first_marker_pos_in_hex = strpos($mozilla_rsa_hex, $object_identifier_hex_marker); // phpcs:ignore
+
+ $second_marker_pos_in_hex_string =
+ strpos($mozilla_rsa_hex, $object_identifier_hex_marker, $first_marker_pos_in_hex + 2);
+
+ if ($second_marker_pos_in_hex_string === false) {
+ throw new WebDriverException('Cannot install extension. Cannot fetch extension commonName');
}
- // Get the extension id from the install manifest.
- $matches = [];
- preg_match('#<' . $prefix . 'id>([^<]+)' . $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);
- } else {
- $this->deleteDirectory($temp_dir);
- throw new WebDriverException('Cannot get the extension id from the install manifest.');
+ $common_name_string_position_in_binary =
+ ($second_marker_pos_in_hex_string + strlen($object_identifier_hex_marker)) / 2;
+
+ $common_name_string_length = ord($mozilla_rsa_binary_data[$common_name_string_position_in_binary + 1]);
+ $addon_common_name = substr(
+ $mozilla_rsa_binary_data,
+ $common_name_string_position_in_binary + 2,
+ $common_name_string_length
+ );
+
+ if (!preg_match('/^\\{[0-9a-f-]{36}\\}$/', $addon_common_name)) {
+ throw new WebDriverException('Cannot install extension. Cannot fetch extension commonName');
}
$this->deleteDirectory($temp_dir);
+ //install extension to profile directory
+ $ext_dir = $profile_dir . '/extensions/';
+ if (!is_dir($ext_dir) && !mkdir($ext_dir, 0777, true) && !is_dir($ext_dir)) {
+ throw new WebDriverException('Cannot install extension - cannot create directory');
+ }
+
+ if (!copy($extension, $ext_dir . $addon_common_name . '.xpi')) {
+ throw new WebDriverException('Cannot install extension - cannot copy file');
+ }
+
+ //extension installation with empty preferences (empty users.js) fails:
+ if (empty($this->preferences)) {
+ $this->setPreference('dom.webdriver.enabled', true);
+ }
+
return $ext_dir;
}
diff --git a/tests/functional/Firefox/FirefoxProfileTest.php b/tests/functional/Firefox/FirefoxProfileTest.php
new file mode 100644
index 000000000..469308553
--- /dev/null
+++ b/tests/functional/Firefox/FirefoxProfileTest.php
@@ -0,0 +1,96 @@
+markTestSkipped('FirefoxProfileTest is run only when running against local firefox');
+ }
+ }
+
+ public function testShouldInstallExtension()
+ {
+ $this->desiredCapabilities = DesiredCapabilities::firefox();
+
+ $firefoxProfile = new FirefoxProfile();
+ $firefoxProfile->addExtension($this->firefoxTestExtensionFilename);
+
+ $this->desiredCapabilities->setCapability(FirefoxDriver::PROFILE, $firefoxProfile);
+
+ $this->driver = RemoteWebDriver::create(
+ $this->serverUrl,
+ $this->desiredCapabilities,
+ $this->connectionTimeout,
+ $this->requestTimeout
+ );
+
+ $this->driver->get($this->getTestPageUrl('index.html'));
+
+ $this->assertInstanceOf(RemoteWebDriver::class, $this->driver);
+
+ $element = $this->driver->findElement(WebDriverBy::id('webDriverExtensionTest'));
+ $this->assertInstanceOf(RemoteWebElement::class, $element);
+
+ $this->driver->quit();
+ }
+
+ public function testShouldInstallExtensionInHeadlessMode()
+ {
+ $this->desiredCapabilities = DesiredCapabilities::firefox();
+
+ $firefoxProfile = new FirefoxProfile();
+ $firefoxProfile->addExtension($this->firefoxTestExtensionFilename);
+
+ $this->desiredCapabilities->setCapability(FirefoxDriver::PROFILE, $firefoxProfile);
+
+ $arguments[] = '--headless';
+ $this->desiredCapabilities->setCapability('moz:firefoxOptions', ['args' => $arguments]);
+
+ $this->driver = RemoteWebDriver::create(
+ $this->serverUrl,
+ $this->desiredCapabilities,
+ $this->connectionTimeout,
+ $this->requestTimeout
+ );
+
+ $this->driver->get($this->getTestPageUrl('index.html'));
+
+ $this->assertInstanceOf(RemoteWebDriver::class, $this->driver);
+
+ $element = $this->driver->findElement(WebDriverBy::id('webDriverExtensionTest'));
+ $this->assertInstanceOf(RemoteWebElement::class, $element);
+
+ $this->driver->quit();
+ }
+}
diff --git a/tests/functional/Fixtures/FirefoxWebdriverTestExtension-0.1-fx.xpi b/tests/functional/Fixtures/FirefoxWebdriverTestExtension-0.1-fx.xpi
new file mode 100644
index 0000000000000000000000000000000000000000..854e14c081de304c0143efb610e544e6dd4d9cdb
GIT binary patch
literal 5384
zcmZ`-2UL^Gwhl!)h!mxl0HH|eO#(;}kS4vCNbfxe7)n5q-a(Kmf*?guiu52o^w1)L
zH0fPB2*Jm>=iTGG=bbzM+H1}F*X%tr-`?}hnomaq51$4A01yG1#Wl5TXV0RZkpln+
zlmNgVf3=hi6u@eaR0Q2UpE|p_Squ31T2E#KN~O8a_YT>(nf4;%-AoxOg+&JqP(~%Rv(k648FWm%9(5fOfIKRCbVgUkVi$Cuo{?^i4zHyHn&Aa{eMfSbb*Krw8Km3NXYV3P0_3`$(dCG@9gmp9t(CMPElNe|c^x!{&V})I}3N
zy5Zs`X)*&YO5;bN7Z2bq-nz{Plepd&UB7@hX46o}IcqyPVK!Ys7tW|w`;E2wVijE=
zaTv{w40$~!fKMUPawtC%JnEm23wLscfw3(++R6)=7SnG8}t0(LXW1UljU(4
zeZU}~oOa5@!_wQ)8k;{Y^1ozUyz3bC(&}%iJ?^+z{@g9_HBFYmfNH2^@x7$f_G|S*
z-A;}3?ciw0w_`JZ#IpQ{^q
zbhMaA6NOT%W<(rH>{{!5V^@TB}Sw)3%Junt&+GN
zskrpfL^h2gLB7NG7%e4+;C8F{?$sm(1zSSJ%n0Lq&kDThaCHfn_7YVJ{9qqL0Eq5|
z%i}BdxX@-GTQ=dR@Fanx6PIB{-4(s&uU@biE|`YKVCD_xpm%7)oyNymld;X`bK9aL
z=E0`57siK^9XTkS&H-IZ@ZO!}wOJ%3LM*^1n0lpQv)vA`O
z#xM45zOn7VR=4$6yoPiprd;8x8+YS2w=OAMp&CVxnF&d1b36%yAi$@kOECWnRK&pQ
zlGV)Q)4duMX&+i~FRJwy{Vioyc8_3%0$Xt#i)S$HlLN21quL$i+SEp;?bxFB25aX?
zeeS6dzo&N_^5HLbNQcQpMs+N#j|NQCm_R<;u3!A2;KSwRd?)>k%Ycqc2BS
zZ{OSI6We>%{KMgpv*M36URPULIRS@b
zNEoZ+%sR|D*hcplnYh}L?mxrpW(m2&ce{u;#ObA%ODO{DEoDjM9nx~N9fGkuMZ~6w
z`#&no9d-_h1W4bZdhHv7eNFrz3h$?X5)-!G2OkH8U5E;hN@s}Xq)I9X%}Rbwx#=&x
zj$;DA0{~bGFLEi`P``k~*wF0;)15$J@vY6_O*>Ry-g&|)OTHEB^w(kr$x(X9B0TBy
z2bm9hBv91S%oz3EV%J{Qp6xm6@iRW$hr6{^Ys?MgG(B0utO+h{qvS*DviiOT%UU92=*85Pm#a-&-n+SyR*)g>1jQo%
zTAEN*;=EZ|P`x_$MuT>apl-Sqh}d{@SiEFtcx}sq+WJ`Cw+yMIWup+7yHQwrI+@9X
z5v^^$sCNnLsKgwWH(d@v$6>Y2BggbNMd>*K
z7H?B0TPNO+io^LFYWdzyDj>F$^{eXN`^|!Nn2$^b_+UTj&
zue{%H8#HZO|L*0Ota#bgGiI0$gFGQK;U~8a0L2PE8zcVtT@865`5^srw@olWFwUHs
z;QR7&xI8ja?Gb>F0_)g;<_i^yG9p9AP$^f{A-!WOto3cg7+grwm+wZ;j7X%To$QH!
zEuzO2*Z|~9`)U$|T!M_xUh5couOLt;H1qWIFUZsB2jLRJm#>X@c=11cb<<{Px+8Q~
z7>8#4fU&XgK?+YYYUl?Qu&_fdbdfz=;53x+3MccYudGBXXHe5a#jwj)erS5X#FVV^
znH%voo%yTbXZBNMpxwNyRvhd>D$45NeX_%#g7eGP;D`ItGxTMQHQ^fZCfQ{
zgG)G~`MYl#z+&UZ?y>aPW`%drfA#*B83{uN>69AiH&u1Oz&Z_ip1;JJs%Ow-3Mz97
za{H3>4>JfoQWdf!B!~hGS+K}Hse`&=BuH*&e$4|XAkI})4afnG=@tRz=Twv
zJ1$l-7THz`lhWR7tc=Po4Gr5Jy2peOj;{_0w7fbsp6B;}eHn}#eBHZ2aVHaENQw`_
ze45r^b!b`~?6D#*$3QBbZ>3I)pc-yR4OZ6YDgv9o_yst4zF^?_BJt)aXu
z6y&2*^_C}MVd4|dY(_L6L#G5e-Xg0q#^v>hh>tZ43+S5QnVvD!93H6T&HXsCa=Ha$
z8f}suE-lV%
z2$UP2Tw+m)>uA3H?66p^NZBZ2A*=Ii*83&S?5~oxqRT7Ey~J|SS+G9Nt;R0W)|rXs
z3ro4dk0Mq_I$2YMA7lp`>hY&Gd+63oPVcQ!@{-w_v5!PtW8k
zr&)DHEZ&AnNgH^txNS7g=cjS8z+a{Ag2iA@BYuqvcnu<4X22Pcy<1Ti8?(_XO76W)
zBRA5>zagu3`49A(As795_ydLG1^PriMfDq*VHM-?>|?DNL^$2a2^g+kb|2#2Hh|6_
zkGAW}kqDrXs-ZOp-pEb3eyn}IHsWiuwzGTS{6xUT*F9dA^qCNivVUlVIZX_#61E=c
z%3VLk{!`#YK~wRdcBsws`B>@riqGC+g>+iiR`R!o!4G3`IA&;ixA%I1`hMoiPQYbO
zssI!GbQ?X$afcUq3lQcR7QgM5$nz_Vr;kmvYm_mU;;rB9ofB}#0r7!&ukYqDY}^+_
zsH!%3iY*+S>l|C@dr{_w+9v$>q5*)M>qTF$^RGs5-E+3}^zaq@_ZT98Ijy+{hfJ%%
zT^s;l0T%!u`)iDsuz>Fq$LY;1v2AjEyE*_;O!FL_D>`32f{@$
z>N<1E-&FH}kKM_x@VG2iv2@femD9x}1=0__^5+#j;ye94zX>`Uy7yL0Yh;d~v~;mB
zg;+LgwbW8BbcEF!TY?jg;ib}tE@i7|z9FRy_{7J7an{U%TZd4qADdlxb4-0C$yv}M
zZM_hj-=G#<1D_WwD>-uwX3;gU*Drm5yS0b2gS{{8x?Vgz?2~3=I)o@A_JU)CGL+3|
zzqCQxRZXTyjny@Kq?;wkwRlL!{O4f|buJzqIeUXSnw1>4DALBz#JMAk70iYN5;hXM
z$;n(VsE|Jz%6Yx^>Em#J$uN9UnJ=UUZ5$Q5z{)^d9A8~_o)@c}shgNC45^ff2+&np
zREt6V$jOkR5G_mn2a-$2-LW54l~g8Ji#alWA(7lV;}=eV$e33+Eslh&YPcMM{u8lbpVFzZ_7HGFdh0Y6t4IC
zr_d2-wo>SHjez-eY5k|r@ozZX9nwdJe5!?L5R0(An?9
zoI^MxzTfWDL*NgI#J%_VRnh_t{^UDV$;8r#;%69}34Y|X782-&d6h9T=VDU?c;Dn<
zuF3tY4T`Oq#c8<$w-d`CKWw5+>27UTYj}KJ-H1rylrSTG)03Q`AoHb7Co`|LM_Vd@
zD~)@tp_SLtMO;H(w*6yaxg_RY>qd#kTly^BvfF+yFSx^Y0>Nnn6kQQlMz1Y$9a!|5
z%*+>i7o%=YEwslzo|!fyj}-v8k{Fh#XADk}saj`)1aU1YTMP%sUL^;uaWt#Wme$nA
z%%q;ugKa
zA=~lL`tXw#eZ9u3d(r~=9+~+%k((z}<7Ih9sVc1D^cpy4xH=j*xHNeGT~52+&c7Ps
zy7K;EXV>D|9}({3{daEv)1M7d8&-FHc>iMh-){fRu7A2wBCrZB6u-Il_f-GHw!f!J
z_{--{?)^O*5#XOF<+tb3&A$=M-x2!zIsDTV06^euTuYF@bN~BP{yoCq>*aTZXH@?;
d!v6}Gz79GXH~zSA0EE}y+v`MV{ZVCr{{iA}wu%4%
literal 0
HcmV?d00001
From dddfd3bd1845dba840bc7e5a796d27140084cd74 Mon Sep 17 00:00:00 2001
From: Alexander Schranz
Date: Sun, 23 Jan 2022 18:19:37 +0100
Subject: [PATCH 031/130] Fix tests and add codestyle exception for Firefox
extension
---
.php-cs-fixer.dist.php | 1 +
lib/Firefox/FirefoxProfile.php | 12 +--
.../Firefox/FirefoxDriverServiceTest.php | 2 +-
.../functional/Firefox/FirefoxDriverTest.php | 2 +-
.../functional/Firefox/FirefoxProfileTest.php | 75 +++++++++----------
5 files changed, 42 insertions(+), 50 deletions(-)
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 051fb6579..5cf7d36f6 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -1,6 +1,7 @@
notPath('Firefox/FirefoxProfile.php') // need to use str_* instead of mb_str_* methods
->in([__DIR__ . '/lib', __DIR__ . '/tests']);
return (new PhpCsFixer\Config())
diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php
index 645d5cae9..b211c97ca 100644
--- a/lib/Firefox/FirefoxProfile.php
+++ b/lib/Firefox/FirefoxProfile.php
@@ -185,8 +185,8 @@ public function encode()
/**
* @param string $extension The path to the extension.
* @param string $profile_dir The path to the profile directory.
- * @throws WebDriverException
* @throws \Exception
+ * @throws WebDriverException
* @return string The path to the directory of this extension.
*/
private function installExtension($extension, $profile_dir)
@@ -207,26 +207,22 @@ private function installExtension($extension, $profile_dir)
$first_marker_pos_in_hex = strpos($mozilla_rsa_hex, $object_identifier_hex_marker); // phpcs:ignore
$second_marker_pos_in_hex_string =
- strpos($mozilla_rsa_hex, $object_identifier_hex_marker, $first_marker_pos_in_hex + 2);
+ strpos($mozilla_rsa_hex, $object_identifier_hex_marker, $first_marker_pos_in_hex + 2); // phpcs:ignore
if ($second_marker_pos_in_hex_string === false) {
throw new WebDriverException('Cannot install extension. Cannot fetch extension commonName');
}
$common_name_string_position_in_binary =
- ($second_marker_pos_in_hex_string + strlen($object_identifier_hex_marker)) / 2;
+ ($second_marker_pos_in_hex_string + strlen($object_identifier_hex_marker)) / 2; // phpcs:ignore
$common_name_string_length = ord($mozilla_rsa_binary_data[$common_name_string_position_in_binary + 1]);
- $addon_common_name = substr(
+ $addon_common_name = substr( // phpcs:ignore
$mozilla_rsa_binary_data,
$common_name_string_position_in_binary + 2,
$common_name_string_length
);
- if (!preg_match('/^\\{[0-9a-f-]{36}\\}$/', $addon_common_name)) {
- throw new WebDriverException('Cannot install extension. Cannot fetch extension commonName');
- }
-
$this->deleteDirectory($temp_dir);
//install extension to profile directory
diff --git a/tests/functional/Firefox/FirefoxDriverServiceTest.php b/tests/functional/Firefox/FirefoxDriverServiceTest.php
index ce110acb7..190286847 100644
--- a/tests/functional/Firefox/FirefoxDriverServiceTest.php
+++ b/tests/functional/Firefox/FirefoxDriverServiceTest.php
@@ -21,7 +21,7 @@ protected function setUp(): void
{
if (getenv('BROWSER_NAME') !== 'firefox' || empty(getenv('GECKODRIVER_PATH'))
|| WebDriverTestCase::isSauceLabsBuild()) {
- $this->markTestSkipped('The test is run only when running against local chrome');
+ $this->markTestSkipped('The test is run only when running against local firefox');
}
}
diff --git a/tests/functional/Firefox/FirefoxDriverTest.php b/tests/functional/Firefox/FirefoxDriverTest.php
index ab6a03846..cc107793a 100644
--- a/tests/functional/Firefox/FirefoxDriverTest.php
+++ b/tests/functional/Firefox/FirefoxDriverTest.php
@@ -22,7 +22,7 @@ protected function setUp(): void
{
if (getenv('BROWSER_NAME') !== 'firefox' || empty(getenv('GECKODRIVER_PATH'))
|| WebDriverTestCase::isSauceLabsBuild()) {
- $this->markTestSkipped('The test is run only when running against local chrome');
+ $this->markTestSkipped('The test is run only when running against local firefox');
}
}
diff --git a/tests/functional/Firefox/FirefoxProfileTest.php b/tests/functional/Firefox/FirefoxProfileTest.php
index 469308553..420dc87f6 100644
--- a/tests/functional/Firefox/FirefoxProfileTest.php
+++ b/tests/functional/Firefox/FirefoxProfileTest.php
@@ -20,40 +20,42 @@
use Facebook\WebDriver\Remote\RemoteWebElement;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverTestCase;
+use PHPUnit\Framework\TestCase;
/**
- * @group firefox
+ * @group exclude-saucelabs
* @covers \Facebook\WebDriver\Firefox\FirefoxProfile
*/
-class FirefoxProfileTest extends WebDriverTestCase
+class FirefoxProfileTest extends TestCase
{
+ /** @var FirefoxDriver */
+ protected $driver;
+
protected $firefoxTestExtensionFilename =
__DIR__ . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'Fixtures/FirefoxWebdriverTestExtension-0.1-fx.xpi';
- protected function setUp()
+ protected function setUp(): void
{
- if (getenv('BROWSER_NAME') !== 'firefox' || getenv('SAUCELABS')) {
- $this->markTestSkipped('FirefoxProfileTest is run only when running against local firefox');
+ if (getenv('BROWSER_NAME') !== 'firefox' || empty(getenv('GECKODRIVER_PATH'))
+ || WebDriverTestCase::isSauceLabsBuild()) {
+ $this->markTestSkipped('The test is run only when running against local firefox');
}
}
- public function testShouldInstallExtension()
+ protected function tearDown(): void
{
- $this->desiredCapabilities = DesiredCapabilities::firefox();
+ if ($this->driver instanceof RemoteWebDriver && $this->driver->getCommandExecutor() !== null) {
+ $this->driver->quit();
+ }
+ }
+ public function testShouldInstallExtension()
+ {
$firefoxProfile = new FirefoxProfile();
$firefoxProfile->addExtension($this->firefoxTestExtensionFilename);
-
- $this->desiredCapabilities->setCapability(FirefoxDriver::PROFILE, $firefoxProfile);
-
- $this->driver = RemoteWebDriver::create(
- $this->serverUrl,
- $this->desiredCapabilities,
- $this->connectionTimeout,
- $this->requestTimeout
- );
+ $this->driver = $this->startFirefoxDriver($firefoxProfile, ['-headless']);
$this->driver->get($this->getTestPageUrl('index.html'));
@@ -61,36 +63,29 @@ public function testShouldInstallExtension()
$element = $this->driver->findElement(WebDriverBy::id('webDriverExtensionTest'));
$this->assertInstanceOf(RemoteWebElement::class, $element);
-
- $this->driver->quit();
}
- public function testShouldInstallExtensionInHeadlessMode()
+ protected function getTestPageUrl($path)
{
- $this->desiredCapabilities = DesiredCapabilities::firefox();
-
- $firefoxProfile = new FirefoxProfile();
- $firefoxProfile->addExtension($this->firefoxTestExtensionFilename);
-
- $this->desiredCapabilities->setCapability(FirefoxDriver::PROFILE, $firefoxProfile);
-
- $arguments[] = '--headless';
- $this->desiredCapabilities->setCapability('moz:firefoxOptions', ['args' => $arguments]);
-
- $this->driver = RemoteWebDriver::create(
- $this->serverUrl,
- $this->desiredCapabilities,
- $this->connectionTimeout,
- $this->requestTimeout
- );
+ $host = 'http://localhost:8000/';
+ if ($alternateHost = getenv('FIXTURES_HOST')) {
+ $host = $alternateHost;
+ }
- $this->driver->get($this->getTestPageUrl('index.html'));
+ return $host . '/' . $path;
+ }
- $this->assertInstanceOf(RemoteWebDriver::class, $this->driver);
+ private function startFirefoxDriver(FirefoxProfile $firefoxProfile, array $arguments = [])
+ {
+ // The createDefaultService() method expect path to the executable to be present in the environment variable
+ putenv(FirefoxDriverService::WEBDRIVER_FIREFOX_DRIVER . '=' . getenv('GECKODRIVER_PATH'));
- $element = $this->driver->findElement(WebDriverBy::id('webDriverExtensionTest'));
- $this->assertInstanceOf(RemoteWebElement::class, $element);
+ $firefoxOptions = new FirefoxOptions();
+ $firefoxOptions->addArguments($arguments);
+ $desiredCapabilities = DesiredCapabilities::firefox();
+ $desiredCapabilities->setCapability(FirefoxOptions::CAPABILITY, $firefoxOptions);
+ $desiredCapabilities->setCapability(FirefoxDriver::PROFILE, $firefoxProfile);
- $this->driver->quit();
+ return FirefoxDriver::start($desiredCapabilities);
}
}
From e297e2b9c301406baa60b01df2dcef53f505c8de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Fri, 26 Aug 2022 14:59:48 +0200
Subject: [PATCH 032/130] Refactor installing Firefox extensions
---
lib/Firefox/FirefoxProfile.php | 97 ++++++++++++++++++----------------
1 file changed, 51 insertions(+), 46 deletions(-)
diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php
index b211c97ca..8e6e1094e 100644
--- a/lib/Firefox/FirefoxProfile.php
+++ b/lib/Firefox/FirefoxProfile.php
@@ -184,63 +184,28 @@ public function encode()
/**
* @param string $extension The path to the extension.
- * @param string $profile_dir The path to the profile directory.
+ * @param string $profileDir The path to the profile directory.
* @throws \Exception
* @throws WebDriverException
- * @return string The path to the directory of this extension.
*/
- private function installExtension($extension, $profile_dir)
+ private function installExtension($extension, $profileDir)
{
- $temp_dir = $this->createTempDirectory();
-
- $this->extractTo($extension, $temp_dir);
-
- $mozilla_rsa_path = $temp_dir . '/META-INF/mozilla.rsa';
- $mozilla_rsa_binary_data = file_get_contents($mozilla_rsa_path);
- $mozilla_rsa_hex = bin2hex($mozilla_rsa_binary_data);
-
- //We need to find plugin id. This is second occurrence of object identifier "2.5.4.3 commonName"
-
- //That is marker "2.5.4.3 commonName" in hex:
- $object_identifier_hex_marker = '0603550403';
-
- $first_marker_pos_in_hex = strpos($mozilla_rsa_hex, $object_identifier_hex_marker); // phpcs:ignore
-
- $second_marker_pos_in_hex_string =
- strpos($mozilla_rsa_hex, $object_identifier_hex_marker, $first_marker_pos_in_hex + 2); // phpcs:ignore
+ $extensionCommonName = $this->parseExtensionName($extension);
- if ($second_marker_pos_in_hex_string === false) {
- throw new WebDriverException('Cannot install extension. Cannot fetch extension commonName');
+ // install extension to profile directory
+ $extensionDir = $profileDir . '/extensions/';
+ if (!is_dir($extensionDir) && !mkdir($extensionDir, 0777, true) && !is_dir($extensionDir)) {
+ throw new WebDriverException('Cannot install Firefox extension - cannot create directory');
}
- $common_name_string_position_in_binary =
- ($second_marker_pos_in_hex_string + strlen($object_identifier_hex_marker)) / 2; // phpcs:ignore
-
- $common_name_string_length = ord($mozilla_rsa_binary_data[$common_name_string_position_in_binary + 1]);
- $addon_common_name = substr( // phpcs:ignore
- $mozilla_rsa_binary_data,
- $common_name_string_position_in_binary + 2,
- $common_name_string_length
- );
-
- $this->deleteDirectory($temp_dir);
-
- //install extension to profile directory
- $ext_dir = $profile_dir . '/extensions/';
- if (!is_dir($ext_dir) && !mkdir($ext_dir, 0777, true) && !is_dir($ext_dir)) {
- throw new WebDriverException('Cannot install extension - cannot create directory');
+ if (!copy($extension, $extensionDir . $extensionCommonName . '.xpi')) {
+ throw new WebDriverException('Cannot install Firefox extension - cannot copy file');
}
- if (!copy($extension, $ext_dir . $addon_common_name . '.xpi')) {
- throw new WebDriverException('Cannot install extension - cannot copy file');
- }
-
- //extension installation with empty preferences (empty users.js) fails:
+ // extension installation with empty preferences (empty users.js) fails, thus add some dummy data
if (empty($this->preferences)) {
- $this->setPreference('dom.webdriver.enabled', true);
+ $this->setPreference('dummy.preference', true);
}
-
- return $ext_dir;
}
/**
@@ -305,4 +270,44 @@ private function extractTo($xpi, $target_dir)
return $this;
}
+
+ private function parseExtensionName($extensionPath)
+ {
+ $temp_dir = $this->createTempDirectory();
+
+ $this->extractTo($extensionPath, $temp_dir);
+
+ $mozillaRsaPath = $temp_dir . '/META-INF/mozilla.rsa';
+ $mozillaRsaBinaryData = file_get_contents($mozillaRsaPath);
+ $mozillaRsaHex = bin2hex($mozillaRsaBinaryData);
+
+ //We need to find the plugin id. This is the second occurrence of object identifier "2.5.4.3 commonName".
+
+ //That is marker "2.5.4.3 commonName" in hex:
+ $objectIdentifierHexMarker = '0603550403';
+
+ $firstMarkerPosInHex = strpos($mozillaRsaHex, $objectIdentifierHexMarker); // phpcs:ignore
+
+ $secondMarkerPosInHexString =
+ strpos($mozillaRsaHex, $objectIdentifierHexMarker, $firstMarkerPosInHex + 2); // phpcs:ignore
+
+ if ($secondMarkerPosInHexString === false) {
+ throw new WebDriverException('Cannot install extension. Cannot fetch extension commonName');
+ }
+
+ // phpcs:ignore
+ $commonNameStringPositionInBinary = ($secondMarkerPosInHexString + strlen($objectIdentifierHexMarker)) / 2;
+
+ $commonNameStringLength = ord($mozillaRsaBinaryData[$commonNameStringPositionInBinary + 1]);
+ // phpcs:ignore
+ $extensionCommonName = substr(
+ $mozillaRsaBinaryData,
+ $commonNameStringPositionInBinary + 2,
+ $commonNameStringLength
+ );
+
+ $this->deleteDirectory($temp_dir);
+
+ return $extensionCommonName;
+ }
}
From 62ee7d0a5695c883308cc4dfd307b78e1281c0d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Machulda?=
Date: Fri, 26 Aug 2022 15:05:46 +0200
Subject: [PATCH 033/130] Update and re-sign Firefox text extension fixture
Also add step-by-step instructions for extension re-validation and re-signing using web-ext tool
---
.../functional/Firefox/FirefoxProfileTest.php | 23 +++++++++++++-----
.../Firefox/Fixtures/FirefoxExtension.xpi | Bin 0 -> 8630 bytes
.../FirefoxWebdriverTestExtension-0.1-fx.xpi | Bin 5384 -> 0 bytes
3 files changed, 17 insertions(+), 6 deletions(-)
create mode 100644 tests/functional/Firefox/Fixtures/FirefoxExtension.xpi
delete mode 100644 tests/functional/Fixtures/FirefoxWebdriverTestExtension-0.1-fx.xpi
diff --git a/tests/functional/Firefox/FirefoxProfileTest.php b/tests/functional/Firefox/FirefoxProfileTest.php
index 420dc87f6..2d44cc6e5 100644
--- a/tests/functional/Firefox/FirefoxProfileTest.php
+++ b/tests/functional/Firefox/FirefoxProfileTest.php
@@ -17,12 +17,26 @@
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
-use Facebook\WebDriver\Remote\RemoteWebElement;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverTestCase;
use PHPUnit\Framework\TestCase;
/**
+ * ## Generating/updating the Firefox extension fixture ##
+ *
+ * For testing purposes, we use dummy Firefox extension (`Fixtures/FirefoxExtension.xpi`), which adds `
` element
+ * with some text at the end of each page Firefox renders.
+ *
+ * In case the extension will need to be modified, steps below must be followed,
+ * otherwise firefox won't load the modified extension:
+ *
+ * - Extract the xpi file (it is a zip archive) to some temporary directory
+ * - Make needed changes in the files
+ * - Install web-ext tool from Mozilla (@see https://github.com/mozilla/web-ext)
+ * - Sign in to https://addons.mozilla.org/cs/developers/addon/api/key/ to get your JWT API key and JWT secret
+ * - Run `web-ext sign --channel=unlisted --api-key=[you-api-key] --api-secret=[your-api-secret]` in the extension dir
+ * - Store the output file (`web-ext-artifacts/[...].xpi`) to the Fixtures/ directory
+ *
* @group exclude-saucelabs
* @covers \Facebook\WebDriver\Firefox\FirefoxProfile
*/
@@ -31,10 +45,7 @@ class FirefoxProfileTest extends TestCase
/** @var FirefoxDriver */
protected $driver;
- protected $firefoxTestExtensionFilename =
- __DIR__ . DIRECTORY_SEPARATOR .
- '..' . DIRECTORY_SEPARATOR .
- 'Fixtures/FirefoxWebdriverTestExtension-0.1-fx.xpi';
+ protected $firefoxTestExtensionFilename = __DIR__ . '/Fixtures/FirefoxExtension.xpi';
protected function setUp(): void
{
@@ -62,7 +73,7 @@ public function testShouldInstallExtension()
$this->assertInstanceOf(RemoteWebDriver::class, $this->driver);
$element = $this->driver->findElement(WebDriverBy::id('webDriverExtensionTest'));
- $this->assertInstanceOf(RemoteWebElement::class, $element);
+ $this->assertEquals('This element was added by browser extension', $element->getText());
}
protected function getTestPageUrl($path)
diff --git a/tests/functional/Firefox/Fixtures/FirefoxExtension.xpi b/tests/functional/Firefox/Fixtures/FirefoxExtension.xpi
new file mode 100644
index 0000000000000000000000000000000000000000..c5805fbeb821161ab0e7644ef0bdfdcf5ba0b7e2
GIT binary patch
literal 8630
zcma)?1yGz_viETYch}(V5`tR@t`j^s!JXh9JOp?5;K3PSaCdi?;O_pB+Hd#GzW46d
z?Ww7nd1}s?)Bn@YneP6Lk}Na~HU!}H@pnUbyF?=u#IXF68#s!*=yfs#xK2$dq)A%X$;%U$9!q~oS`$|yv?I9vnTdWB2=v7
z5|i