From 1a4f7a1fc682e5d338e55580480862daa83acec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 9 Jan 2020 14:58:19 +0100 Subject: [PATCH 001/276] Remove 'any' when present in W3C platformName capabilitites --- lib/Remote/DesiredCapabilities.php | 5 +++++ lib/WebDriverPlatform.php | 1 + tests/unit/Remote/DesiredCapabilitiesTest.php | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 1e49eb9f5..ac634de86 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -229,6 +229,11 @@ public function toW3cCompatibleArray() if (array_key_exists($capabilityKey, static::$ossToW3c)) { if ($capabilityKey === WebDriverCapabilityType::PLATFORM) { $w3cCapabilities[static::$ossToW3c[$capabilityKey]] = mb_strtolower($capabilityValue); + + // Remove platformName if it is set to "any" + if ($w3cCapabilities[static::$ossToW3c[$capabilityKey]] === 'any') { + unset($w3cCapabilities[static::$ossToW3c[$capabilityKey]]); + } } else { $w3cCapabilities[static::$ossToW3c[$capabilityKey]] = $capabilityValue; } diff --git a/lib/WebDriverPlatform.php b/lib/WebDriverPlatform.php index 5609eb0b8..4cf4c2b1a 100644 --- a/lib/WebDriverPlatform.php +++ b/lib/WebDriverPlatform.php @@ -23,6 +23,7 @@ class WebDriverPlatform { const ANDROID = 'ANDROID'; + /** @deprecated */ const ANY = 'ANY'; const LINUX = 'LINUX'; const MAC = 'MAC'; diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index 04075b458..7949ec447 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -187,7 +187,7 @@ public function provideW3cCapabilities() ]), [], ], - 'already W3C capabilitites' => [ + 'already W3C capabilities' => [ new DesiredCapabilities([ 'pageLoadStrategy' => 'eager', 'strictFileInteractability' => false, @@ -197,6 +197,12 @@ public function provideW3cCapabilities() 'strictFileInteractability' => false, ], ], + '"ANY" platform should be completely removed' => [ + new DesiredCapabilities([ + WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, + ]), + [], + ], 'custom vendor extension' => [ new DesiredCapabilities([ 'vendor:prefix' => 'vendor extension should be kept', From e32ccb149d99d28e79f742267c5378b398e4d542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 14 Jan 2020 19:02:38 +0100 Subject: [PATCH 002/276] Change license to MIT --- LICENSE.md | 223 ++---------------- composer.json | 2 +- example.php | 13 - lib/AbstractWebDriverCheckboxOrRadio.php | 13 - lib/Chrome/ChromeDriver.php | 13 - lib/Chrome/ChromeDriverService.php | 13 - lib/Chrome/ChromeOptions.php | 13 - lib/Cookie.php | 13 - .../ElementClickInterceptedException.php | 13 - .../ElementNotInteractableException.php | 13 - .../ElementNotSelectableException.php | 13 - lib/Exception/ElementNotVisibleException.php | 13 - lib/Exception/ExpectedException.php | 13 - .../IMEEngineActivationFailedException.php | 13 - lib/Exception/IMENotAvailableException.php | 13 - lib/Exception/IndexOutOfBoundsException.php | 13 - .../InsecureCertificateException.php | 13 - lib/Exception/InvalidArgumentException.php | 13 - .../InvalidCookieDomainException.php | 13 - lib/Exception/InvalidCoordinatesException.php | 13 - .../InvalidElementStateException.php | 13 - lib/Exception/InvalidSelectorException.php | 13 - lib/Exception/InvalidSessionIdException.php | 13 - lib/Exception/JavascriptErrorException.php | 13 - .../MoveTargetOutOfBoundsException.php | 13 - lib/Exception/NoAlertOpenException.php | 13 - lib/Exception/NoCollectionException.php | 13 - lib/Exception/NoScriptResultException.php | 13 - lib/Exception/NoStringException.php | 13 - lib/Exception/NoStringLengthException.php | 13 - lib/Exception/NoStringWrapperException.php | 13 - lib/Exception/NoSuchAlertException.php | 13 - lib/Exception/NoSuchCollectionException.php | 13 - lib/Exception/NoSuchCookieException.php | 13 - lib/Exception/NoSuchDocumentException.php | 13 - lib/Exception/NoSuchDriverException.php | 13 - lib/Exception/NoSuchElementException.php | 13 - lib/Exception/NoSuchFrameException.php | 13 - lib/Exception/NoSuchWindowException.php | 13 - lib/Exception/NullPointerException.php | 13 - lib/Exception/ScriptTimeoutException.php | 13 - lib/Exception/SessionNotCreatedException.php | 13 - .../StaleElementReferenceException.php | 13 - lib/Exception/TimeoutException.php | 13 - .../UnableToCaptureScreenException.php | 13 - lib/Exception/UnableToSetCookieException.php | 13 - .../UnexpectedAlertOpenException.php | 13 - .../UnexpectedJavascriptException.php | 13 - lib/Exception/UnexpectedTagNameException.php | 13 - lib/Exception/UnknownCommandException.php | 13 - lib/Exception/UnknownErrorException.php | 13 - lib/Exception/UnknownMethodException.php | 13 - lib/Exception/UnknownServerException.php | 13 - .../UnrecognizedExceptionException.php | 13 - .../UnsupportedOperationException.php | 13 - lib/Exception/WebDriverCurlException.php | 13 - lib/Exception/WebDriverException.php | 13 - lib/Exception/XPathLookupException.php | 13 - lib/Firefox/FirefoxDriver.php | 13 - lib/Firefox/FirefoxPreferences.php | 13 - lib/Firefox/FirefoxProfile.php | 13 - .../Internal/WebDriverButtonReleaseAction.php | 13 - .../Internal/WebDriverClickAction.php | 13 - .../Internal/WebDriverClickAndHoldAction.php | 13 - .../Internal/WebDriverContextClickAction.php | 13 - .../Internal/WebDriverCoordinates.php | 13 - .../Internal/WebDriverDoubleClickAction.php | 13 - .../Internal/WebDriverKeyDownAction.php | 13 - .../Internal/WebDriverKeyUpAction.php | 13 - .../Internal/WebDriverKeysRelatedAction.php | 13 - .../Internal/WebDriverMouseAction.php | 13 - .../Internal/WebDriverMouseMoveAction.php | 13 - .../Internal/WebDriverMoveToOffsetAction.php | 13 - .../Internal/WebDriverSendKeysAction.php | 13 - .../Internal/WebDriverSingleKeyAction.php | 13 - .../Touch/WebDriverDoubleTapAction.php | 13 - .../Touch/WebDriverDownAction.php | 13 - .../Touch/WebDriverFlickAction.php | 13 - .../Touch/WebDriverFlickFromElementAction.php | 13 - .../Touch/WebDriverLongPressAction.php | 13 - .../Touch/WebDriverMoveAction.php | 13 - .../Touch/WebDriverScrollAction.php | 13 - .../WebDriverScrollFromElementAction.php | 13 - lib/Interactions/Touch/WebDriverTapAction.php | 13 - .../Touch/WebDriverTouchAction.php | 13 - .../Touch/WebDriverTouchScreen.php | 13 - lib/Interactions/WebDriverActions.php | 13 - lib/Interactions/WebDriverCompositeAction.php | 13 - lib/Interactions/WebDriverTouchActions.php | 13 - lib/Internal/WebDriverLocatable.php | 13 - lib/JavaScriptExecutor.php | 13 - lib/Net/URLChecker.php | 13 - lib/Remote/DesiredCapabilities.php | 13 - lib/Remote/DriverCommand.php | 13 - lib/Remote/ExecuteMethod.php | 13 - lib/Remote/FileDetector.php | 13 - lib/Remote/HttpCommandExecutor.php | 13 - lib/Remote/JsonWireCompat.php | 13 - lib/Remote/LocalFileDetector.php | 13 - lib/Remote/RemoteExecuteMethod.php | 13 - lib/Remote/RemoteKeyboard.php | 13 - lib/Remote/RemoteMouse.php | 13 - lib/Remote/RemoteStatus.php | 13 - lib/Remote/RemoteTargetLocator.php | 13 - lib/Remote/RemoteTouchScreen.php | 13 - lib/Remote/RemoteWebDriver.php | 13 - lib/Remote/RemoteWebElement.php | 13 - lib/Remote/Service/DriverCommandExecutor.php | 13 - lib/Remote/Service/DriverService.php | 13 - lib/Remote/UselessFileDetector.php | 13 - lib/Remote/WebDriverBrowserType.php | 13 - lib/Remote/WebDriverCapabilityType.php | 13 - lib/Remote/WebDriverCommand.php | 13 - lib/Remote/WebDriverResponse.php | 13 - lib/Support/Events/EventFiringWebDriver.php | 13 - .../Events/EventFiringWebDriverNavigation.php | 13 - lib/Support/Events/EventFiringWebElement.php | 13 - lib/Support/XPathEscaper.php | 13 - lib/WebDriver.php | 13 - lib/WebDriverAction.php | 13 - lib/WebDriverAlert.php | 13 - lib/WebDriverBy.php | 13 - lib/WebDriverCapabilities.php | 13 - lib/WebDriverCheckboxes.php | 13 - lib/WebDriverCommandExecutor.php | 13 - lib/WebDriverDimension.php | 13 - lib/WebDriverDispatcher.php | 13 - lib/WebDriverElement.php | 13 - lib/WebDriverEventListener.php | 13 - lib/WebDriverExpectedCondition.php | 13 - lib/WebDriverHasInputDevices.php | 13 - lib/WebDriverKeyboard.php | 13 - lib/WebDriverKeys.php | 13 - lib/WebDriverMouse.php | 13 - lib/WebDriverNavigation.php | 13 - lib/WebDriverOptions.php | 13 - lib/WebDriverPlatform.php | 13 - lib/WebDriverPoint.php | 13 - lib/WebDriverRadios.php | 13 - lib/WebDriverSearchContext.php | 13 - lib/WebDriverSelect.php | 13 - lib/WebDriverSelectInterface.php | 13 - lib/WebDriverTargetLocator.php | 13 - lib/WebDriverTimeouts.php | 13 - lib/WebDriverUpAction.php | 13 - lib/WebDriverWait.php | 13 - lib/WebDriverWindow.php | 13 - tests/bootstrap.php | 13 - .../Chrome/ChromeDriverServiceTest.php | 13 - tests/functional/Chrome/ChromeDriverTest.php | 13 - tests/functional/FileUploadTest.php | 13 - tests/functional/RemoteKeyboardTest.php | 13 - tests/functional/RemoteTargetLocatorTest.php | 13 - .../functional/RemoteWebDriverCreateTest.php | 13 - .../RemoteWebDriverFindElementTest.php | 13 - tests/functional/RemoteWebDriverTest.php | 13 - tests/functional/RemoteWebElementTest.php | 13 - .../ReportSauceLabsStatusListener.php | 13 - tests/functional/WebDriverActionsTest.php | 13 - tests/functional/WebDriverAlertTest.php | 13 - tests/functional/WebDriverByTest.php | 13 - tests/functional/WebDriverCheckboxesTest.php | 13 - tests/functional/WebDriverNavigationTest.php | 13 - .../WebDriverOptionsCookiesTest.php | 13 - tests/functional/WebDriverRadiosTest.php | 13 - tests/functional/WebDriverSelectTest.php | 13 - tests/functional/WebDriverTestCase.php | 13 - tests/functional/WebDriverTimeoutsTest.php | 13 - tests/functional/web/slow_pixel.png.php | 13 - tests/functional/web/submit.php | 13 - tests/functional/web/upload.php | 13 - tests/unit/CookieTest.php | 13 - .../unit/Exception/WebDriverExceptionTest.php | 13 - .../WebDriverButtonReleaseActionTest.php | 13 - .../Internal/WebDriverClickActionTest.php | 13 - .../WebDriverClickAndHoldActionTest.php | 13 - .../WebDriverContextClickActionTest.php | 13 - .../Internal/WebDriverCoordinatesTest.php | 13 - .../WebDriverDoubleClickActionTest.php | 13 - .../Internal/WebDriverKeyDownActionTest.php | 13 - .../Internal/WebDriverKeyUpActionTest.php | 13 - .../Internal/WebDriverMouseMoveActionTest.php | 13 - .../WebDriverMouseToOffsetActionTest.php | 13 - .../Internal/WebDriverSendKeysActionTest.php | 13 - tests/unit/Remote/DesiredCapabilitiesTest.php | 13 - tests/unit/Remote/HttpCommandExecutorTest.php | 13 - tests/unit/Remote/RemoteWebDriverTest.php | 13 - tests/unit/Remote/RemoteWebElementTest.php | 13 - tests/unit/Remote/WebDriverCommandTest.php | 13 - tests/unit/Support/XPathEscaperTest.php | 13 - tests/unit/WebDriverExpectedConditionTest.php | 13 - tests/unit/WebDriverKeysTest.php | 13 - tests/unit/WebDriverOptionsTest.php | 13 - 193 files changed, 23 insertions(+), 2685 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 0b3f67bd7..611fa7390 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,201 +1,22 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2004-present Facebook - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +MIT License + +Copyright (c) 2004-2020 Facebook +Copyright (c) 2020-present [open-source contributors](https://github.com/php-webdriver/php-webdriver/graphs/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/composer.json b/composer.json index d422149ee..d31c8d2a6 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "keywords": ["webdriver", "selenium", "php", "facebook"], "homepage": "https://github.com/facebook/php-webdriver", "type": "library", - "license": "Apache-2.0", + "license": "MIT", "support": { "issues": "https://github.com/facebook/php-webdriver/issues", "forum": "https://www.facebook.com/groups/phpwebdriver/", diff --git a/example.php b/example.php index 4dbb93900..ab7464a3a 100644 --- a/example.php +++ b/example.php @@ -1,17 +1,4 @@ diff --git a/tests/functional/web/upload.php b/tests/functional/web/upload.php index 0bac36c3a..71143d46c 100644 --- a/tests/functional/web/upload.php +++ b/tests/functional/web/upload.php @@ -1,17 +1,4 @@ diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 3df705e2a..621fb65c0 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -1,17 +1,4 @@ Date: Tue, 14 Jan 2020 18:39:34 +0100 Subject: [PATCH 003/276] Rename repository to php-webdriver/php-webdriver --- README.md | 6 +++--- composer.json | 9 ++------- tests/functional/RemoteWebDriverTest.php | 2 +- tests/functional/web/index.html | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 71742583b..c7242088b 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ versions of Chrome and Chromedriver with just a slight limitations. The concepts of this library are very similar to the "official" Java, .NET, Python and Ruby bindings from the [Selenium project](https://github.com/SeleniumHQ/selenium/). -Looking for API documentation of php-webdriver? See [https://facebook.github.io/php-webdriver/](https://facebook.github.io/php-webdriver/latest/) +Looking for API documentation of php-webdriver? See [https://php-webdriver.github.io/php-webdriver/](https://php-webdriver.github.io/php-webdriver/latest/) Any complaints, questions, or ideas? Post them in the user group https://www.facebook.com/groups/phpwebdriver/. @@ -94,7 +94,7 @@ For latest changes see [CHANGELOG.md](CHANGELOG.md) file. ## More information -Some how-tos are provided right here in [our GitHub wiki](https://github.com/facebook/php-webdriver/wiki). +Some how-tos are provided right here in [our GitHub wiki](https://github.com/php-webdriver/php-webdriver/wiki). You may also want to check out the Selenium [docs](http://docs.seleniumhq.org/docs/) and [wiki](https://github.com/SeleniumHQ/selenium/wiki). @@ -113,7 +113,7 @@ We have a great community willing to help you! - **Via our Facebook Group** - If you have questions or are an active contributor consider joining our [facebook group](https://www.facebook.com/groups/phpwebdriver/) and contribute to communal discussion and support - **Via StackOverflow** - You can also [ask a question](https://stackoverflow.com/questions/ask?tags=php+selenium-webdriver) or find many already answered question on StackOverflow -- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/facebook/php-webdriver/issues/new) as a new issue +- **Via GitHub** - Another option if you have a question (or bug report) is to [submit it here](https://github.com/php-webdriver/php-webdriver/issues/new) as a new issue ## Contributing diff --git a/composer.json b/composer.json index d31c8d2a6..9e4a00e68 100644 --- a/composer.json +++ b/composer.json @@ -1,15 +1,10 @@ { "name": "facebook/webdriver", "description": "A PHP client for Selenium WebDriver", - "keywords": ["webdriver", "selenium", "php", "facebook"], - "homepage": "https://github.com/facebook/php-webdriver", + "keywords": ["webdriver", "selenium", "php"], + "homepage": "https://github.com/php-webdriver/php-webdriver", "type": "library", "license": "MIT", - "support": { - "issues": "https://github.com/facebook/php-webdriver/issues", - "forum": "https://www.facebook.com/groups/phpwebdriver/", - "source": "https://github.com/facebook/php-webdriver" - }, "minimum-stability": "beta", "require": { "php": "^5.6 || ~7.0", diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index afbf3baf6..28b4e52ab 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -44,7 +44,7 @@ public function testShouldGetPageSource() $source = $this->driver->getPageSource(); $this->assertContains('

', $source); - $this->assertContains('Welcome to the facebook/php-webdriver testing page.', $source); + $this->assertContains('Welcome to the php-webdriver testing page.', $source); } /** diff --git a/tests/functional/web/index.html b/tests/functional/web/index.html index d94ba31f9..02c42e9d6 100644 --- a/tests/functional/web/index.html +++ b/tests/functional/web/index.html @@ -18,7 +18,7 @@
-

Welcome to the facebook/php-webdriver testing page.

+

Welcome to the php-webdriver testing page.

Form test page | From 71aff82f2a6c9bc5ea4805f25af82915a87297e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 15 Jan 2020 00:38:07 +0100 Subject: [PATCH 004/276] Remove Facebook CLA requirement --- CONTRIBUTING.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 741a140a9..b7fa587cc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,8 +16,6 @@ The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) 4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md) 5. Submit your [pull request](https://github.com/facebook/php-webdriver/pulls) against community branch -Note before any pull request can be accepted, a [Contributors Licensing Agreement](https://developers.facebook.com/opensource/cla) must be signed. - When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. FYI, here is the overview of [the official Java API](http://seleniumhq.github.io/selenium/docs/api/java/) From 7e75d88d17dd76095f88b8b748c7276696d03c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 26 Dec 2019 03:29:56 +0100 Subject: [PATCH 005/276] Migrate codestyle check to GitHub actions --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 0 .../ISSUE_TEMPLATE.md | 0 .github/workflows/php.yaml | 30 +++++++++++++++++++ .travis.yml | 14 --------- 4 files changed, 30 insertions(+), 14 deletions(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%) rename ISSUE_TEMPLATE.md => .github/ISSUE_TEMPLATE.md (100%) create mode 100644 .github/workflows/php.yaml diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md similarity index 100% rename from ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE.md diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml new file mode 100644 index 000000000..04fd5b9da --- /dev/null +++ b/.github/workflows/php.yaml @@ -0,0 +1,30 @@ +name: PHP + +on: + push: + pull_request: + schedule: + - cron: '0 3 * * *' + +jobs: + analyze: + name: "Code style and static analysis" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: '7.4' + extensions: mbstring, intl, zip + + - name: Install dependencies + run: | + composer update --no-interaction + composer require phpstan/phpstan # Not part of require-dev, because it won't install on PHP 5.6 + + - name: Run checks + run: | + composer analyze + composer codestyle:check diff --git a/.travis.yml b/.travis.yml index aa9bce590..517535f4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,20 +20,6 @@ services: matrix: include: - # Codestyle check build - - name: 'Code style and static analysis' - php: '7.4' - env: CHECK_CODESTYLE=1 - before_install: - - phpenv config-rm xdebug.ini - before_script: ~ - script: - - composer require phpstan/phpstan # Not part of require-dev, because it won't install on PHP 5.6 - - composer analyze - - composer codestyle:check - after_script: ~ - after_success: ~ - # Build with lowest possible dependencies on lowest possible PHP - name: 'Lowest dependencies build' php: '5.6' From 1cb715acd554fdc13a7c812fdb72d1d603d893bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 16 Jan 2020 14:08:19 +0100 Subject: [PATCH 006/276] Update URL and JWT of Travis builds --- .travis.yml | 8 ++++---- README.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 517535f4b..a773b2c6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,7 +80,7 @@ matrix: addons: sauce_connect: true jwt: - secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - name: 'Sauce Labs, Chrome 74, OSS protocol' php: '7.3' @@ -91,7 +91,7 @@ matrix: addons: sauce_connect: true jwt: - secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - name: 'Sauce Labs, Chrome latest, W3C protocol' php: '7.3' @@ -102,7 +102,7 @@ matrix: addons: sauce_connect: true jwt: - secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - name: 'Sauce Labs, Edge latest, W3C protocol' php: '7.3' @@ -113,7 +113,7 @@ matrix: addons: sauce_connect: true jwt: - secure: HPq5xFhosa1eSGnaRdJzeyEuaE0mhRlG1gf3G7+dKS0VniF30husSyrxZhbGCCKBGxmIySoAQzd43BCwL69EkUEVKDN87Cpid1Ce9KrSfU3cnN8XIb+4QINyy7x1a47RUAfaaOEx53TrW0ShalvjD+ZwDE8LrgagSox6KQ+nQLE= + secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= cache: directories: diff --git a/README.md b/README.md index c7242088b..3d24af5df 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # php-webdriver – Selenium WebDriver bindings for PHP [![Latest Stable Version](https://img.shields.io/packagist/v/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) -[![Travis Build](https://img.shields.io/travis/facebook/php-webdriver/community.svg?style=flat-square)](https://travis-ci.org/facebook/php-webdriver) +[![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/community.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) [![Sauce Test Status](https://saucelabs.com/buildstatus/php-webdriver)](https://saucelabs.com/u/php-webdriver) [![Total Downloads](https://img.shields.io/packagist/dt/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) [![License](https://img.shields.io/packagist/l/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) From d97761cf0ff988cee255d62854c9eb9442721ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 16 Jan 2020 13:43:59 +0100 Subject: [PATCH 007/276] Rename Packagist package to php-webdriver/webdriver --- README.md | 7 +++---- composer.json | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3d24af5df..affefa390 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ # php-webdriver – Selenium WebDriver bindings for PHP -[![Latest Stable Version](https://img.shields.io/packagist/v/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) +[![Latest Stable Version](https://img.shields.io/packagist/v/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) [![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/community.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) [![Sauce Test Status](https://saucelabs.com/buildstatus/php-webdriver)](https://saucelabs.com/u/php-webdriver) -[![Total Downloads](https://img.shields.io/packagist/dt/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) -[![License](https://img.shields.io/packagist/l/facebook/webdriver.svg?style=flat-square)](https://packagist.org/packages/facebook/webdriver) +[![Total Downloads](https://img.shields.io/packagist/dt/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) ## Description Php-webdriver library is PHP language binding for Selenium WebDriver, which allows you to control web browsers from PHP. @@ -33,7 +32,7 @@ If you don't already use Composer, you can download the `composer.phar` binary: Then install the library: - php composer.phar require facebook/webdriver + php composer.phar require php-webdriver/webdriver ## Getting started diff --git a/composer.json b/composer.json index 9e4a00e68..58ab593b4 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { - "name": "facebook/webdriver", - "description": "A PHP client for Selenium WebDriver", - "keywords": ["webdriver", "selenium", "php"], + "name": "php-webdriver/webdriver", + "description": "A PHP client for Selenium WebDriver. Previously facebook/php-webdriver.", + "keywords": ["webdriver", "selenium", "php", "geckodriver", "chromedriver"], "homepage": "https://github.com/php-webdriver/php-webdriver", "type": "library", "license": "MIT", From 79e3b832c5e36437caf822c349ff1b931427ef43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 16 Jan 2020 15:54:31 +0100 Subject: [PATCH 008/276] Include information about renaming in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15d1d2524..f9317baab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - `takeElementScreenshot()` method of `RemoteWebElement` to do the obvious - take screenshot of the particular element. ### Changed +- The repository was migrated to [`php-webdriver/php-webdriver`](https://github.com/php-webdriver/php-webdriver/). +- The Packagist package was renamed to [`php-webdriver/webdriver`](https://packagist.org/packages/php-webdriver/webdriver) and the original [`facebook/webdriver`](https://packagist.org/packages/facebook/webdriver) was marked as abandoned. - Revert no longer needed workaround for Chromedriver bug [2943](https://bugs.chromium.org/p/chromedriver/issues/detail?id=2943). - Allow installation of Symfony 5 components. - Rename environment variable used to pass path to ChromeDriver executable from `webdriver.chrome.driver` to `WEBDRIVER_CHROME_DRIVER`. However the old one also still works to keep backward compatibility From 79e9fcacea3777528dbe6addff4fa3d603695689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 17 Jan 2020 13:03:00 +0100 Subject: [PATCH 009/276] Show downloads/day badge --- README.md | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index affefa390..e05ff8526 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Latest Stable Version](https://img.shields.io/packagist/v/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) [![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/community.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) [![Sauce Test Status](https://saucelabs.com/buildstatus/php-webdriver)](https://saucelabs.com/u/php-webdriver) -[![Total Downloads](https://img.shields.io/packagist/dt/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) +[![Total Downloads](https://img.shields.io/packagist/dd/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) ## Description Php-webdriver library is PHP language binding for Selenium WebDriver, which allows you to control web browsers from PHP. diff --git a/composer.json b/composer.json index 58ab593b4..f370c2fb0 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "php-webdriver/webdriver", - "description": "A PHP client for Selenium WebDriver. Previously facebook/php-webdriver.", + "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.", "keywords": ["webdriver", "selenium", "php", "geckodriver", "chromedriver"], "homepage": "https://github.com/php-webdriver/php-webdriver", "type": "library", From 4767e547c6d26ea2b245cc4fc9801b0bf744a21b Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Wed, 11 Dec 2019 21:35:51 +0800 Subject: [PATCH 010/276] Window maximize does not take args in w3c --- lib/WebDriverWindow.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index b92caa0fc..3a703b35f 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -88,10 +88,14 @@ public function minimize() */ public function maximize() { - $this->executor->execute( - DriverCommand::MAXIMIZE_WINDOW, - [':windowHandle' => 'current'] - ); + if ($this->isW3cCompliant) { + $this->executor->execute(DriverCommand::MAXIMIZE_WINDOW, []); + } else { + $this->executor->execute( + DriverCommand::MAXIMIZE_WINDOW, + [':windowHandle' => 'current'] + ); + } return $this; } From 393f30cc6a2ce4b538d1c22357a0a9c53b648438 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Wed, 11 Dec 2019 21:40:33 +0800 Subject: [PATCH 011/276] Add fullscreen window command Part of #683 --- lib/Remote/DriverCommand.php | 1 + lib/Remote/HttpCommandExecutor.php | 1 + lib/WebDriverWindow.php | 16 ++++++++++++++++ tests/functional/WebDriverWindowTest.php | 24 ++++++++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index 867e0cd32..34daf3e42 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -125,6 +125,7 @@ class DriverCommand const GET_WINDOW_SIZE = 'getWindowSize'; const GET_WINDOW_POSITION = 'getWindowPosition'; const MAXIMIZE_WINDOW = 'maximizeWindow'; + const FULLSCREEN_WINDOW = 'fullscreenWindow'; // Logging API const GET_AVAILABLE_LOG_TYPES = 'getAvailableLogTypes'; const GET_LOG = 'getLog'; diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 08ca9c1c2..dcaa1374c 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -140,6 +140,7 @@ class HttpCommandExecutor implements WebDriverCommandExecutor DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/alert/dismiss'], DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/async'], DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute/sync'], + DriverCommand::FULLSCREEN_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window/fullscreen'], DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'GET', 'url' => '/session/:sessionId/element/active'], DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert/text'], DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window'], diff --git a/lib/WebDriverWindow.php b/lib/WebDriverWindow.php index 3a703b35f..e212f92ed 100644 --- a/lib/WebDriverWindow.php +++ b/lib/WebDriverWindow.php @@ -100,6 +100,22 @@ public function maximize() return $this; } + /** + * Makes the current window full screen. + * + * @return WebDriverWindow The instance. + */ + public function fullscreen() + { + if (!$this->isW3cCompliant) { + throw new UnsupportedOperationException('The Fullscreen window command is only supported in W3C mode'); + } + + $this->executor->execute(DriverCommand::FULLSCREEN_WINDOW, []); + + return $this; + } + /** * Set the size of the current window. This will change the outer window * dimension, not just the view port. diff --git a/tests/functional/WebDriverWindowTest.php b/tests/functional/WebDriverWindowTest.php index fb11abe2a..6b2671b81 100644 --- a/tests/functional/WebDriverWindowTest.php +++ b/tests/functional/WebDriverWindowTest.php @@ -48,6 +48,30 @@ public function testShouldMaximizeWindow() $this->assertGreaterThanOrEqual($sizeBefore->getHeight(), $sizeAfter->getHeight()); } + /** + * @group exclude-edge + */ + public function testShouldFullscreenWindow() + { + self::skipForJsonWireProtocol('"fullscreen" window is not supported in JsonWire protocol'); + + $this->driver->manage() + ->window() + ->setSize(new WebDriverDimension(400, 300)); + + $this->driver->manage() + ->window() + ->fullscreen(); + + $sizeAfter = $this->driver->manage() + ->window() + ->getSize(); + + // Note: Headless browsers see no effect. + $this->assertGreaterThanOrEqual(400, $sizeAfter->getWidth()); + $this->assertGreaterThanOrEqual(300, $sizeAfter->getHeight()); + } + /** * @group exclude-saucelabs * @group exclude-chrome From a806290e992f320a92b693d3ba069e7b23541409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 24 Jan 2020 15:52:33 +0100 Subject: [PATCH 012/276] Change community branch to master #739 --- .github/CONTRIBUTING.md | 4 ++-- README.md | 2 +- composer.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b7fa587cc..2fdbb677f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,7 +2,7 @@ We love to have your help to make php-webdriver better! -Feel free to open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem, or +Feel free to open an [issue](https://github.com/php-webdriver/php-webdriver/issues) if you run into any problem, or send a pull request (see bellow) with your contribution. ## Code of Conduct @@ -14,7 +14,7 @@ The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) 2. Implement your code changes into separate branch 3. Make sure all PHPUnit tests passes and code-style matches PSR-2 (see below). We also have Travis CI build which will automatically run tests on your pull request. 4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md) -5. Submit your [pull request](https://github.com/facebook/php-webdriver/pulls) against community branch +5. Submit your [pull request](https://github.com/php-webdriver/php-webdriver/pulls) against `master` branch When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. FYI, here is the overview of [the official Java API](http://seleniumhq.github.io/selenium/docs/api/java/) diff --git a/README.md b/README.md index e05ff8526..199d210e5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # php-webdriver – Selenium WebDriver bindings for PHP [![Latest Stable Version](https://img.shields.io/packagist/v/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) -[![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/community.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) +[![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/master.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) [![Sauce Test Status](https://saucelabs.com/buildstatus/php-webdriver)](https://saucelabs.com/u/php-webdriver) [![Total Downloads](https://img.shields.io/packagist/dd/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) diff --git a/composer.json b/composer.json index f370c2fb0..aa8ab5a1d 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ }, "extra": { "branch-alias": { - "dev-community": "1.8.x-dev" + "dev-master": "1.8.x-dev" } } } From 95becf6a53f921b1ec2ff2f85a3b90405968b907 Mon Sep 17 00:00:00 2001 From: Maxim Leontyev Date: Fri, 26 Oct 2018 14:52:28 +0300 Subject: [PATCH 013/276] Support of custom http WebDriver commands --- lib/Remote/DriverCommand.php | 2 + lib/Remote/HttpCommandExecutor.php | 50 +++++++++++++----- lib/Remote/RemoteWebDriver.php | 25 +++++++++ lib/Remote/WebDriverCommand.php | 52 +++++++++++++++++++ tests/unit/Remote/HttpCommandExecutorTest.php | 33 +++++++++++- tests/unit/Remote/WebDriverCommandTest.php | 24 +++++++++ 6 files changed, 171 insertions(+), 15 deletions(-) diff --git a/lib/Remote/DriverCommand.php b/lib/Remote/DriverCommand.php index 34daf3e42..3f1e8392d 100644 --- a/lib/Remote/DriverCommand.php +++ b/lib/Remote/DriverCommand.php @@ -133,6 +133,8 @@ class DriverCommand // Mobile API const GET_NETWORK_CONNECTION = 'getNetworkConnection'; const SET_NETWORK_CONNECTION = 'setNetworkConnection'; + // Custom command + const CUSTOM_COMMAND = 'customCommand'; // W3C specific const ACTIONS = 'actions'; diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index dcaa1374c..9510ab491 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -130,6 +130,7 @@ class HttpCommandExecutor implements WebDriverCommandExecutor DriverCommand::TOUCH_MOVE => ['method' => 'POST', 'url' => '/session/:sessionId/touch/move'], DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'], DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'], + DriverCommand::CUSTOM_COMMAND => false, ]; /** * @var array Will be merged with $commands @@ -262,21 +263,10 @@ public function setRequestTimeout($timeout_in_ms) */ public function execute(WebDriverCommand $command) { - $commandName = $command->getName(); - if (!isset(self::$commands[$commandName])) { - if ($this->isW3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) { - throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); - } - } + $http_options = $this->getCommandHttpOptions($command); + $http_method = $http_options['method']; + $url = $http_options['url']; - if ($this->isW3cCompliant) { - $raw = self::$w3cCompliantCommands[$command->getName()]; - } else { - $raw = self::$commands[$command->getName()]; - } - - $http_method = $raw['method']; - $url = $raw['url']; $url = str_replace(':sessionId', $command->getSessionID(), $url); $params = $command->getParameters(); foreach ($params as $name => $value) { @@ -400,4 +390,36 @@ public function getAddressOfRemoteServer() { return $this->url; } + + /** + * @return array + */ + protected function getCommandHttpOptions(WebDriverCommand $command) + { + $commandName = $command->getName(); + if (!isset(self::$commands[$commandName])) { + if ($this->isW3cCompliant && !isset(self::$w3cCompliantCommands[$commandName])) { + throw new InvalidArgumentException($command->getName() . ' is not a valid command.'); + } + } + + if ($this->isW3cCompliant) { + $raw = self::$w3cCompliantCommands[$command->getName()]; + } else { + $raw = self::$commands[$command->getName()]; + } + + if ($raw === false) { + $url = $command->getCustomUrl(); + $method = $command->getCustomMethod(); + } else { + $url = $raw['url']; + $method = $raw['method']; + } + + return [ + 'url' => $url, + 'method' => $method, + ]; + } } diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 5cac97247..358e31405 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -589,6 +589,31 @@ public function execute($command_name, $params = []) return null; } + /** + * @param string $url + * @param string $method + * @param array $params + * @return mixed|null + */ + public function executeCustomCommand($url, $method = 'GET', $params = []) + { + $command = new WebDriverCommand( + $this->sessionID, + DriverCommand::CUSTOM_COMMAND, + $params + ); + + $command->setCustomRequestParameters($url, $method); + + if ($this->executor) { + $response = $this->executor->execute($command); + + return $response->getValue(); + } + + return null; + } + /** * @internal * @return bool diff --git a/lib/Remote/WebDriverCommand.php b/lib/Remote/WebDriverCommand.php index 9b893697a..e1a693c7f 100644 --- a/lib/Remote/WebDriverCommand.php +++ b/lib/Remote/WebDriverCommand.php @@ -2,14 +2,22 @@ namespace Facebook\WebDriver\Remote; +use Facebook\WebDriver\Exception\WebDriverException; + class WebDriverCommand { + const METHOD_GET = 'GET'; + const METHOD_POST = 'POST'; /** @var string */ private $sessionID; /** @var string */ private $name; /** @var array */ private $parameters; + /** @var string */ + private $customUrl; + /** @var string */ + private $customMethod; /** * @param string $session_id @@ -47,4 +55,48 @@ public function getParameters() { return $this->parameters; } + + /** + * @param string $custom_url + * @param string $custom_method + * @throws WebDriverException + */ + public function setCustomRequestParameters($custom_url, $custom_method) + { + if (!in_array($custom_method, [static::METHOD_GET, static::METHOD_POST])) { + throw new WebDriverException('Invalid custom method'); + } + $this->customMethod = $custom_method; + + if (mb_substr($custom_url, 0, 1) !== '/') { + throw new WebDriverException('Custom url should start with /'); + } + $this->customUrl = $custom_url; + } + + /** + * @throws WebDriverException + * @return string + */ + public function getCustomUrl() + { + if ($this->customUrl === null) { + throw new WebDriverException('Custom url is not set'); + } + + return $this->customUrl; + } + + /** + * @throws WebDriverException + * @return string + */ + public function getCustomMethod() + { + if ($this->customUrl === null) { + throw new WebDriverException('Custom url is not set'); + } + + return $this->customMethod; + } } diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php index af7670b06..43c5859c9 100644 --- a/tests/unit/Remote/HttpCommandExecutorTest.php +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -24,16 +24,25 @@ protected function setUp() * @param bool $shouldResetExpectHeader * @param string $expectedUrl * @param string $expectedPostData + * @param null|array $customCommandParameters */ public function testShouldSendRequestToAssembledUrl( $command, array $params, $shouldResetExpectHeader, $expectedUrl, - $expectedPostData + $expectedPostData, + $customCommandParameters = null ) { $command = new WebDriverCommand('foo-123', $command, $params); + if ($customCommandParameters !== null) { + $command->setCustomRequestParameters( + $customCommandParameters['url'], + $customCommandParameters['method'] + ); + } + $curlSetoptMock = $this->getFunctionMock(__NAMESPACE__, 'curl_setopt'); $curlSetoptMock->expects($this->at(0)) ->with($this->anything(), CURLOPT_URL, $expectedUrl); @@ -106,6 +115,28 @@ public function provideCommand() 'http://localhost:4444/sessions', null, ], + 'Custom GET command' => [ + DriverCommand::CUSTOM_COMMAND, + [':someParameter' => 'someValue'], + false, + 'http://localhost:4444/session/foo-123/custom-command/someValue', + null, + [ + 'url' => '/session/:sessionId/custom-command/:someParameter', + 'method' => 'GET', + ], + ], + 'Custom POST command' => [ + DriverCommand::CUSTOM_COMMAND, + ['someParameter' => 'someValue'], + true, + 'http://localhost:4444/session/foo-123/custom-post-command/', + '{"someParameter":"someValue"}', + [ + 'url' => '/session/:sessionId/custom-post-command/', + 'method' => 'POST', + ], + ], ]; } } diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php index 0bf6efb20..39177dca1 100644 --- a/tests/unit/Remote/WebDriverCommandTest.php +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -2,6 +2,7 @@ namespace Facebook\WebDriver\Remote; +use Facebook\WebDriver\Exception\WebDriverException; use PHPUnit\Framework\TestCase; class WebDriverCommandTest extends TestCase @@ -14,4 +15,27 @@ public function testShouldSetOptionsUsingConstructor() $this->assertSame('bar-baz-name', $command->getName()); $this->assertSame(['foo' => 'bar'], $command->getParameters()); } + + public function testCustomCommandInit() + { + $command = new WebDriverCommand('session-id-123', 'customCommand', ['foo' => 'bar']); + $command->setCustomRequestParameters('/some-url', 'POST'); + + $this->assertSame('/some-url', $command->getCustomUrl()); + $this->assertSame('POST', $command->getCustomMethod()); + } + + public function testCustomCommandInvalidUrlExceptionInit() + { + $this->expectException(WebDriverException::class); + $command = new WebDriverCommand('session-id-123', 'customCommand', ['foo' => 'bar']); + $command->setCustomRequestParameters('url-without-leading-slash', 'POST'); + } + + public function testCustomCommandInvalidMethodExceptionInit() + { + $this->expectException(WebDriverException::class); + $command = new WebDriverCommand('session-id-123', 'customCommand', ['foo' => 'bar']); + $command->setCustomRequestParameters('/some-url', 'invalid-method'); + } } From 5e0d2071214796a76b2aadf0b9efe06e57bc1f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 22 Jan 2020 14:05:36 +0100 Subject: [PATCH 014/276] Refactor custom commands --- lib/Remote/CustomWebDriverCommand.php | 82 +++++++++++++++++++ lib/Remote/HttpCommandExecutor.php | 4 +- lib/Remote/RemoteWebDriver.php | 11 ++- lib/Remote/WebDriverCommand.php | 58 +------------ .../Remote/CustomWebDriverCommandTest.php | 38 +++++++++ tests/unit/Remote/HttpCommandExecutorTest.php | 76 +++++++---------- tests/unit/Remote/WebDriverCommandTest.php | 24 ------ 7 files changed, 161 insertions(+), 132 deletions(-) create mode 100644 lib/Remote/CustomWebDriverCommand.php create mode 100644 tests/unit/Remote/CustomWebDriverCommandTest.php diff --git a/lib/Remote/CustomWebDriverCommand.php b/lib/Remote/CustomWebDriverCommand.php new file mode 100644 index 000000000..157902199 --- /dev/null +++ b/lib/Remote/CustomWebDriverCommand.php @@ -0,0 +1,82 @@ +setCustomRequestParameters($url, $method); + + parent::__construct($session_id, DriverCommand::CUSTOM_COMMAND, $parameters); + } + + /** + * @throws WebDriverException + * @return string + */ + public function getCustomUrl() + { + if ($this->customUrl === null) { + throw new WebDriverException('URL of custom command is not set'); + } + + return $this->customUrl; + } + + /** + * @throws WebDriverException + * @return string + */ + public function getCustomMethod() + { + if ($this->customMethod === null) { + throw new WebDriverException('Method of custom command is not set'); + } + + return $this->customMethod; + } + + /** + * @param string $custom_url + * @param string $custom_method + * @throws WebDriverException + */ + protected function setCustomRequestParameters($custom_url, $custom_method) + { + $allowedMethods = [static::METHOD_GET, static::METHOD_POST]; + if (!in_array($custom_method, $allowedMethods, true)) { + throw new WebDriverException( + sprintf( + 'Invalid custom method "%s", must be one of [%s]', + $custom_method, + implode(', ', $allowedMethods) + ) + ); + } + $this->customMethod = $custom_method; + + if (mb_strpos($custom_url, '/') !== 0) { + throw new WebDriverException( + sprintf('URL of custom command has to start with / but is "%s"', $custom_url) + ); + } + $this->customUrl = $custom_url; + } +} diff --git a/lib/Remote/HttpCommandExecutor.php b/lib/Remote/HttpCommandExecutor.php index 9510ab491..6bc942adf 100644 --- a/lib/Remote/HttpCommandExecutor.php +++ b/lib/Remote/HttpCommandExecutor.php @@ -130,7 +130,7 @@ class HttpCommandExecutor implements WebDriverCommandExecutor DriverCommand::TOUCH_MOVE => ['method' => 'POST', 'url' => '/session/:sessionId/touch/move'], DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'], DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'], - DriverCommand::CUSTOM_COMMAND => false, + DriverCommand::CUSTOM_COMMAND => [], ]; /** * @var array Will be merged with $commands @@ -409,7 +409,7 @@ protected function getCommandHttpOptions(WebDriverCommand $command) $raw = self::$commands[$command->getName()]; } - if ($raw === false) { + if ($command instanceof CustomWebDriverCommand) { $url = $command->getCustomUrl(); $method = $command->getCustomMethod(); } else { diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 358e31405..f157fdf06 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -590,21 +590,20 @@ public function execute($command_name, $params = []) } /** - * @param string $url + * @param string $endpointUrl * @param string $method * @param array $params * @return mixed|null */ - public function executeCustomCommand($url, $method = 'GET', $params = []) + public function executeCustomCommand($endpointUrl, $method = 'GET', $params = []) { - $command = new WebDriverCommand( + $command = new CustomWebDriverCommand( $this->sessionID, - DriverCommand::CUSTOM_COMMAND, + $endpointUrl, + $method, $params ); - $command->setCustomRequestParameters($url, $method); - if ($this->executor) { $response = $this->executor->execute($command); diff --git a/lib/Remote/WebDriverCommand.php b/lib/Remote/WebDriverCommand.php index e1a693c7f..e21fbdaae 100644 --- a/lib/Remote/WebDriverCommand.php +++ b/lib/Remote/WebDriverCommand.php @@ -2,22 +2,14 @@ namespace Facebook\WebDriver\Remote; -use Facebook\WebDriver\Exception\WebDriverException; - class WebDriverCommand { - const METHOD_GET = 'GET'; - const METHOD_POST = 'POST'; /** @var string */ - private $sessionID; + protected $sessionID; /** @var string */ - private $name; + protected $name; /** @var array */ - private $parameters; - /** @var string */ - private $customUrl; - /** @var string */ - private $customMethod; + protected $parameters; /** * @param string $session_id @@ -55,48 +47,4 @@ public function getParameters() { return $this->parameters; } - - /** - * @param string $custom_url - * @param string $custom_method - * @throws WebDriverException - */ - public function setCustomRequestParameters($custom_url, $custom_method) - { - if (!in_array($custom_method, [static::METHOD_GET, static::METHOD_POST])) { - throw new WebDriverException('Invalid custom method'); - } - $this->customMethod = $custom_method; - - if (mb_substr($custom_url, 0, 1) !== '/') { - throw new WebDriverException('Custom url should start with /'); - } - $this->customUrl = $custom_url; - } - - /** - * @throws WebDriverException - * @return string - */ - public function getCustomUrl() - { - if ($this->customUrl === null) { - throw new WebDriverException('Custom url is not set'); - } - - return $this->customUrl; - } - - /** - * @throws WebDriverException - * @return string - */ - public function getCustomMethod() - { - if ($this->customUrl === null) { - throw new WebDriverException('Custom url is not set'); - } - - return $this->customMethod; - } } diff --git a/tests/unit/Remote/CustomWebDriverCommandTest.php b/tests/unit/Remote/CustomWebDriverCommandTest.php new file mode 100644 index 000000000..b56bc4aea --- /dev/null +++ b/tests/unit/Remote/CustomWebDriverCommandTest.php @@ -0,0 +1,38 @@ + 'bar'] + ); + + $this->assertSame('/some-url', $command->getCustomUrl()); + $this->assertSame('POST', $command->getCustomMethod()); + } + + public function testCustomCommandInvalidUrlExceptionInit() + { + $this->expectException(WebDriverException::class); + $this->expectExceptionMessage('URL of custom command has to start with / but is "url-without-leading-slash"'); + + new CustomWebDriverCommand('session-id-123', 'url-without-leading-slash', 'POST', []); + } + + public function testCustomCommandInvalidMethodExceptionInit() + { + $this->expectException(WebDriverException::class); + $this->expectExceptionMessage('Invalid custom method "invalid-method", must be one of [GET, POST]'); + + new CustomWebDriverCommand('session-id-123', '/some-url', 'invalid-method', []); + } +} diff --git a/tests/unit/Remote/HttpCommandExecutorTest.php b/tests/unit/Remote/HttpCommandExecutorTest.php index 43c5859c9..d76780463 100644 --- a/tests/unit/Remote/HttpCommandExecutorTest.php +++ b/tests/unit/Remote/HttpCommandExecutorTest.php @@ -19,30 +19,17 @@ protected function setUp() /** * @dataProvider provideCommand - * @param int $command - * @param array $params + * @param WebDriverCommand $command * @param bool $shouldResetExpectHeader * @param string $expectedUrl - * @param string $expectedPostData - * @param null|array $customCommandParameters + * @param string|null $expectedPostData */ public function testShouldSendRequestToAssembledUrl( - $command, - array $params, + WebDriverCommand $command, $shouldResetExpectHeader, $expectedUrl, - $expectedPostData, - $customCommandParameters = null + $expectedPostData ) { - $command = new WebDriverCommand('foo-123', $command, $params); - - if ($customCommandParameters !== null) { - $command->setCustomRequestParameters( - $customCommandParameters['url'], - $customCommandParameters['method'] - ); - } - $curlSetoptMock = $this->getFunctionMock(__NAMESPACE__, 'curl_setopt'); $curlSetoptMock->expects($this->at(0)) ->with($this->anything(), CURLOPT_URL, $expectedUrl); @@ -81,61 +68,60 @@ public function provideCommand() { return [ 'POST command having :id placeholder in url' => [ - DriverCommand::SEND_KEYS_TO_ELEMENT, - ['value' => 'submitted-value', ':id' => '1337'], + new WebDriverCommand( + 'fooSession', + DriverCommand::SEND_KEYS_TO_ELEMENT, + ['value' => 'submitted-value', ':id' => '1337'] + ), true, - 'http://localhost:4444/session/foo-123/element/1337/value', + 'http://localhost:4444/session/fooSession/element/1337/value', '{"value":"submitted-value"}', ], 'POST command without :id placeholder in url' => [ - DriverCommand::TOUCH_UP, - ['x' => 3, 'y' => 6], + new WebDriverCommand('fooSession', DriverCommand::TOUCH_UP, ['x' => 3, 'y' => 6]), true, - 'http://localhost:4444/session/foo-123/touch/up', + 'http://localhost:4444/session/fooSession/touch/up', '{"x":3,"y":6}', ], 'Extra useless placeholder parameter should be removed' => [ - DriverCommand::TOUCH_UP, - ['x' => 3, 'y' => 6, ':useless' => 'foo'], + new WebDriverCommand('fooSession', DriverCommand::TOUCH_UP, ['x' => 3, 'y' => 6, ':useless' => 'foo']), true, - 'http://localhost:4444/session/foo-123/touch/up', + 'http://localhost:4444/session/fooSession/touch/up', '{"x":3,"y":6}', ], 'DELETE command' => [ - DriverCommand::DELETE_COOKIE, - [':name' => 'cookie-name'], + new WebDriverCommand('fooSession', DriverCommand::DELETE_COOKIE, [':name' => 'cookie-name']), false, - 'http://localhost:4444/session/foo-123/cookie/cookie-name', + 'http://localhost:4444/session/fooSession/cookie/cookie-name', null, ], 'GET command without session in URL' => [ - DriverCommand::GET_ALL_SESSIONS, - [], + new WebDriverCommand('fooSession', DriverCommand::GET_ALL_SESSIONS, []), false, 'http://localhost:4444/sessions', null, ], 'Custom GET command' => [ - DriverCommand::CUSTOM_COMMAND, - [':someParameter' => 'someValue'], + new CustomWebDriverCommand( + 'fooSession', + '/session/:sessionId/custom-command/:someParameter', + 'GET', + [':someParameter' => 'someValue'] + ), false, - 'http://localhost:4444/session/foo-123/custom-command/someValue', + 'http://localhost:4444/session/fooSession/custom-command/someValue', null, - [ - 'url' => '/session/:sessionId/custom-command/:someParameter', - 'method' => 'GET', - ], ], 'Custom POST command' => [ - DriverCommand::CUSTOM_COMMAND, - ['someParameter' => 'someValue'], + new CustomWebDriverCommand( + 'fooSession', + '/session/:sessionId/custom-post-command/', + 'POST', + ['someParameter' => 'someValue'] + ), true, - 'http://localhost:4444/session/foo-123/custom-post-command/', + 'http://localhost:4444/session/fooSession/custom-post-command/', '{"someParameter":"someValue"}', - [ - 'url' => '/session/:sessionId/custom-post-command/', - 'method' => 'POST', - ], ], ]; } diff --git a/tests/unit/Remote/WebDriverCommandTest.php b/tests/unit/Remote/WebDriverCommandTest.php index 39177dca1..0bf6efb20 100644 --- a/tests/unit/Remote/WebDriverCommandTest.php +++ b/tests/unit/Remote/WebDriverCommandTest.php @@ -2,7 +2,6 @@ namespace Facebook\WebDriver\Remote; -use Facebook\WebDriver\Exception\WebDriverException; use PHPUnit\Framework\TestCase; class WebDriverCommandTest extends TestCase @@ -15,27 +14,4 @@ public function testShouldSetOptionsUsingConstructor() $this->assertSame('bar-baz-name', $command->getName()); $this->assertSame(['foo' => 'bar'], $command->getParameters()); } - - public function testCustomCommandInit() - { - $command = new WebDriverCommand('session-id-123', 'customCommand', ['foo' => 'bar']); - $command->setCustomRequestParameters('/some-url', 'POST'); - - $this->assertSame('/some-url', $command->getCustomUrl()); - $this->assertSame('POST', $command->getCustomMethod()); - } - - public function testCustomCommandInvalidUrlExceptionInit() - { - $this->expectException(WebDriverException::class); - $command = new WebDriverCommand('session-id-123', 'customCommand', ['foo' => 'bar']); - $command->setCustomRequestParameters('url-without-leading-slash', 'POST'); - } - - public function testCustomCommandInvalidMethodExceptionInit() - { - $this->expectException(WebDriverException::class); - $command = new WebDriverCommand('session-id-123', 'customCommand', ['foo' => 'bar']); - $command->setCustomRequestParameters('/some-url', 'invalid-method'); - } } From f5a1b0d998b4188d2bb2d0e362768b21d8c346d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 3 Feb 2020 12:30:41 +0100 Subject: [PATCH 015/276] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9317baab..645ffd936 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). - Experimental W3C WebDriver protocol support. The protocol will be used automatically when remote end (like Geckodriver, newer Chromedriver etc.) supports it. - `getStatus()` method of `RemoteWebDriver` to get information about remote-end readiness to create new sessions. - `takeElementScreenshot()` method of `RemoteWebElement` to do the obvious - take screenshot of the particular element. +- Support for sending custom commands via `executeCustomCommand()`. See [wiki](https://github.com/php-webdriver/php-webdriver/wiki/Custom-commands) for more information. ### Changed - The repository was migrated to [`php-webdriver/php-webdriver`](https://github.com/php-webdriver/php-webdriver/). From bb8d3707b06b3313fac511b53dce2fbaa14382af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 16 Dec 2019 16:29:14 +0100 Subject: [PATCH 016/276] Update example.php to use Wikipedia website --- composer.json | 2 +- example.php | 71 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/composer.json b/composer.json index aa8ab5a1d..77df01f21 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" ], "analyze": [ - "vendor/bin/parallel-lint -j 10 ./lib ./tests", + "vendor/bin/parallel-lint -j 10 ./lib ./tests example.php", "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi" ] }, diff --git a/example.php b/example.php index ab7464a3a..be2c5eaa3 100644 --- a/example.php +++ b/example.php @@ -1,7 +1,7 @@ get('https://www.seleniumhq.org/'); +$driver = RemoteWebDriver::create($host, $capabilities); -// adding cookie -$driver->manage()->deleteAllCookies(); +// navigate to Selenium page on Wikipedia +$driver->get('https://en.wikipedia.org/wiki/Selenium_(software)'); -$cookie = new Cookie('cookie_name', 'cookie_value'); -$driver->manage()->addCookie($cookie); +// write 'PHP' in the search box +$driver->findElement(WebDriverBy::id('searchInput')) // find search input element + ->sendKeys('PHP') // fill the search box + ->submit(); // submit the whole form -$cookies = $driver->manage()->getCookies(); -print_r($cookies); +// wait until 'PHP' is shown in the page heading element +$driver->wait()->until( + WebDriverExpectedCondition::elementTextContains(WebDriverBy::id('firstHeading'), 'PHP') +); + +// print title of the current page to output +echo "The title is '" . $driver->getTitle() . "'\n"; + +// print URL of current page to output +echo "The current URL is '" . $driver->getCurrentURL() . "'\n"; -// click the link 'About' -$link = $driver->findElement( - WebDriverBy::id('menu_about') +// find element of 'History' item in menu +$historyButton = $driver->findElement( + WebDriverBy::cssSelector('#ca-history a') ); -$link->click(); -// wait until the page is loaded +// read text of the element and print it to output +echo "About to click to button with text: '" . $historyButton->getText() . "'\n"; + +// click the element to navigate to revision history page +$historyButton->click(); + +// wait until the target page is loaded $driver->wait()->until( - WebDriverExpectedCondition::titleContains('About') + WebDriverExpectedCondition::titleContains('Revision history') ); // print the title of the current page echo "The title is '" . $driver->getTitle() . "'\n"; // print the URI of the current page + echo "The current URI is '" . $driver->getCurrentURL() . "'\n"; -// write 'php' in the search box -$driver->findElement(WebDriverBy::id('q')) - ->sendKeys('php') // fill the search box - ->submit(); // submit the whole form +// delete all cookies +$driver->manage()->deleteAllCookies(); + +// add new cookie +$cookie = new Cookie('cookie_set_by_selenium', 'cookie_value'); +$driver->manage()->addCookie($cookie); + +// dump current cookies to output +$cookies = $driver->manage()->getCookies(); +print_r($cookies); -// wait at most 10 seconds until at least one result is shown -$driver->wait(10)->until( - WebDriverExpectedCondition::presenceOfAllElementsLocatedBy( - WebDriverBy::className('gsc-result') - ) -); // close the browser $driver->quit(); From 8994d572eb7142ab2e2aefcbaa007e2e82e0f515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 16 Dec 2019 16:29:46 +0100 Subject: [PATCH 017/276] Baby yoda does not have a place here --- lib/Remote/RemoteWebElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index cb0caee46..fff018e41 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -392,7 +392,7 @@ public function submit() // cannot call the submit method directly in case an input of this form is named "submit" 'script' => sprintf( 'return Object.getPrototypeOf(%1$s).submit.call(%1$s);', - 'form' === $this->getTagName() ? 'arguments[0]' : 'arguments[0].form' + $this->getTagName() === 'form' ? 'arguments[0]' : 'arguments[0].form' ), 'args' => [[JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $this->id]], ]); From a2e7a9cdd4ff7ddf061ba483bded1d73ee9b59d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 3 Feb 2020 17:37:50 +0100 Subject: [PATCH 018/276] Mention Symfony Panther and Laravel Dusk in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 199d210e5..c9f4550cc 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ You may also want to check out the Selenium [docs](http://docs.seleniumhq.org/do To take advantage of automatized testing you may want to integrate php-webdriver to your testing framework. There are some projects already providing this: +- [Symfony Panther](https://github.com/symfony/panther) uses php-webdriver and integrates with PHPUnit using `PantherTestCase` +- [Laravel Dusk](https://laravel.com/docs/dusk) is another project using php-webdriver, could be used for testing via `DuskTestCase` - [Steward](https://github.com/lmc-eu/steward) integrates php-webdriver directly to [PHPUnit](https://phpunit.de/), and provides parallelization - [Codeception](http://codeception.com) testing framework provides BDD-layer on top of php-webdriver in its [WebDriver module](http://codeception.com/docs/modules/WebDriver) - You can also check out this [blogpost](http://codeception.com/11-12-2013/working-with-phpunit-and-selenium-webdriver.html) + [demo project](https://github.com/DavertMik/php-webdriver-demo), describing simple [PHPUnit](https://phpunit.de/) integration From c17361f92ccbc389ecafcfe55179696c7a761ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 5 Feb 2020 23:12:38 +0100 Subject: [PATCH 019/276] Exclude fullscreen test from chrome Because of Chrome 80 regression: https://bugs.chromium.org/p/chromium/issues/detail?id=1049336 --- tests/functional/WebDriverWindowTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/WebDriverWindowTest.php b/tests/functional/WebDriverWindowTest.php index 6b2671b81..ba0b45187 100644 --- a/tests/functional/WebDriverWindowTest.php +++ b/tests/functional/WebDriverWindowTest.php @@ -50,6 +50,8 @@ public function testShouldMaximizeWindow() /** * @group exclude-edge + * @group exclude-chrome + * @see https://bugs.chromium.org/p/chromium/issues/detail?id=1049336 */ public function testShouldFullscreenWindow() { From 29f054fefd7cc4d776b3370cb43c95094689b0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 4 Feb 2020 16:38:35 +0100 Subject: [PATCH 020/276] Extend and improve readme --- README.md | 121 +++++++++++++++++++++++++++++++++++++++++----------- example.php | 1 - 2 files changed, 96 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c9f4550cc..25d7d29de 100644 --- a/README.md +++ b/README.md @@ -36,66 +36,137 @@ Then install the library: ## Getting started -### Start Server +### 1. Start server (aka. remote end) -The required server is the `selenium-server-standalone-#.jar` file provided here: http://selenium-release.storage.googleapis.com/index.html +To control a browser, you need to start a *remote end* (server), which will listen to the commands sent +from this library and will execute them in the respective browser. -Download and run the server by **replacing #** with the current server version. Keep in mind **you must have Java 8+ installed to run this command**. +This could be Selenium standalone server, but for local development, you can send them directly to so-called "browser driver" like Chromedriver or Geckodriver. - java -jar selenium-server-standalone-#.jar +#### a) Chromedriver -### Create a Browser Session +Install the latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads). +Make sure to have a compatible version of Chromedriver and Chrome! -When creating a browser session, be sure to pass the url of your running server. +Run `chromedriver` binary, you can pass `port` argument, so that it listens on port 4444: -```php -// This would be the url of the host running the server-standalone.jar -$host = 'http://localhost:4444/wd/hub'; // this is the default url and port where Selenium server starts +```sh +chromedriver --port=4444 ``` -##### Launch Chrome +#### b) Geckodriver -Install latest Chrome and [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads). +Install the latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases). +Make sure to have a compatible version of Geckodriver and Firefox! -The `chromedriver` binary must be placed in system `PATH` directory, otherwise you must provide the path when starting Selenium server -(eg. `java -Dwebdriver.chrome.driver="/path/to/chromedriver" -jar selenium-server-standalone-#.jar`). +Run `geckodriver` binary (it start to listen on port 4444 by default): -```php -$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); +```sh +geckodriver +``` + +#### c) Selenium standalone server + +[Selenium server](https://selenium.dev/downloads/) is useful especially when you need to execute multiple tests at once +or your tests are run in different browsers - like on your CI server. + +Selenium server receives commands and starts new sessions using browser drivers acting like hub distributing the commands +among multiple nodes. + +To run the standalone server, download [`selenium-server-standalone-#.jar` file](http://selenium-release.storage.googleapis.com/index.html) +(replace # with the current server version). Keep in mind **you must have Java 8+ installed**. + +Run the server: + +```sh +java -jar selenium-server-standalone-#.jar +``` + +You may need to provide path to `chromedriver`/`geckodriver` binary (if they are not placed in system `PATH` directory): + +```sh +# Chromedriver: +java -Dwebdriver.chrome.driver="/opt/chromium-browser/chromedriver" -jar vendor/bin/selenium-server-standalone-#.jar +# Geckodriver: +java -Dwebdriver.gecko.driver="/home/john/bin/geckodriver" -jar vendor/bin/selenium-server-standalone-#.jar + +# (These options could be combined) ``` -##### Launch Firefox +If you want to distribute browser sessions among multiple servers ("grid mode" - one Selenium hub and multiple Selenium nodes) please +[refer to the documentation](https://selenium.dev/documentation/en/grid/). + +#### d) Docker -Install latest Firefox and [Geckodriver](https://github.com/mozilla/geckodriver/releases). +Selenium server could also be started inside Docker container - see [docker-selenium project](https://github.com/SeleniumHQ/docker-selenium). -The `geckodriver` binary must be placed in system `PATH` directory, otherwise you must provide the path when starting Selenium server -(eg. `java -Dwebdriver.gecko.driver="/path/to/geckodriver" -jar selenium-server-standalone-#.jar`). +### 2. Create a Browser Session +When creating a browser session, be sure to pass the url of your running server. + +For example: + +```php +// Chromedriver (if started using --port=4444 as above) +$host = 'http://localhost:4444/'; +// Geckodriver +$host = 'http://localhost:4444/'; +// selenium-server-standalone-#.jar (version 2.x or 3.x) +$host = 'http://localhost:4444/wd/hub'; +// selenium-server-standalone-#.jar (version 4.x) +$host = 'http://localhost:4444/'; +``` + +Now you can start browser of your choice: ```php +use Facebook\WebDriver\Remote\RemoteWebDriver; + +// Chrome +$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); +// Firefox $driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox()); +// Microsoft Edge +$driver = RemoteWebDriver::create($host, DesiredCapabilities::microsoftEdge()); ``` -### Customize Desired Capabilities +### 3. Customize Desired Capabilities + +Desired capabilities define properties of the browser you are about to start. + +They can be customized: ```php +use Facebook\WebDriver\Remote\DesiredCapabilities; + $desiredCapabilities = DesiredCapabilities::firefox(); + +// Disable accepting SSL certificates $desiredCapabilities->setCapability('acceptSslCerts', false); + +// Run headless firefox +$desiredCapabilities->setCapability('moz:firefoxOptions', ['args' => ['-headless']]); + $driver = RemoteWebDriver::create($host, $desiredCapabilities); ``` -* See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities for more details. +They can also be used to [configure proxy server](https://github.com/php-webdriver/php-webdriver/wiki/HowTo-Work-with-proxy) which the browser should use. +To configure Chrome, you may use ChromeOptions - see [details in our wiki](https://github.com/php-webdriver/php-webdriver/wiki/ChromeOptions). -**NOTE:** Above snippets are not intended to be a working example by simply copy-pasting. See [example.php](example.php) for working example. +* See [legacy JsonWire protocol](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities) documentation or [W3C WebDriver specification](https://w3c.github.io/webdriver/#capabilities) for more details. + +**NOTE:** Above snippets are not intended to be a working example by simply copy-pasting. See [example.php](example.php) for a working example. ## Changelog For latest changes see [CHANGELOG.md](CHANGELOG.md) file. ## More information -Some how-tos are provided right here in [our GitHub wiki](https://github.com/php-webdriver/php-webdriver/wiki). +Some basic usage example is provided in [example.php](example.php) file. + +How-tos are provided right here in [our GitHub wiki](https://github.com/php-webdriver/php-webdriver/wiki). -You may also want to check out the Selenium [docs](http://docs.seleniumhq.org/docs/) and [wiki](https://github.com/SeleniumHQ/selenium/wiki). +You may also want to check out the Selenium [docs](https://selenium.dev/documentation/en/) and [wiki](https://github.com/SeleniumHQ/selenium/wiki). ## Testing framework integration @@ -118,4 +189,4 @@ We have a great community willing to help you! ## Contributing -We love to have your help to make php-webdriver better. See [CONTRIBUTING.md](CONTRIBUTING.md) for more information about contributing and developing php-webdriver. +We love to have your help to make php-webdriver better. See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for more information about contributing and developing php-webdriver. diff --git a/example.php b/example.php index be2c5eaa3..b7daac7bc 100644 --- a/example.php +++ b/example.php @@ -70,6 +70,5 @@ $cookies = $driver->manage()->getCookies(); print_r($cookies); - // close the browser $driver->quit(); From 1b13ddf96cc007560f8522309a2b0e17d53cccb5 Mon Sep 17 00:00:00 2001 From: Kaz Date: Wed, 5 Feb 2020 10:11:16 +0100 Subject: [PATCH 021/276] Attempt to upload the file to the remote browser even in W3C mode --- lib/Remote/RemoteWebElement.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index fff018e41..1e6a217f2 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -341,8 +341,17 @@ public function sendKeys($value) } } else { if ($this->isW3cCompliant) { + try { + // Attempt to upload the file to the remote browser. + // This is so far non-W3C compliant method, so it may fail - if so, we just ignore the exception. + // @see https://github.com/w3c/webdriver/issues/1355 + $fileName = $this->upload($local_file); + } catch (WebDriverException $e) { + $fileName = $local_file; + } + $params = [ - 'text' => $local_file, + 'text' => $fileName, ':id' => $this->id, ]; } else { From 748901162c03a4df7610e44da01907262d4fce50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 6 Feb 2020 12:23:24 +0100 Subject: [PATCH 022/276] Add few missing unit tests --- lib/Remote/RemoteTargetLocator.php | 4 ++-- tests/functional/RemoteTargetLocatorTest.php | 6 +++++ tests/unit/Remote/DesiredCapabilitiesTest.php | 15 ++++++++++++ tests/unit/Remote/LocalFileDetectorTest.php | 24 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/unit/Remote/LocalFileDetectorTest.php diff --git a/lib/Remote/RemoteTargetLocator.php b/lib/Remote/RemoteTargetLocator.php index a5bd9e03c..fb5b552bc 100644 --- a/lib/Remote/RemoteTargetLocator.php +++ b/lib/Remote/RemoteTargetLocator.php @@ -27,8 +27,8 @@ public function __construct($executor, $driver, $isW3cCompliant = false) } /** - * Switch to the main document if the page contains iframes. Otherwise, switch - * to the first frame on the page. + * Set the current browsing context to the current top-level browsing context. + * This is the same as calling `RemoteTargetLocator::frame(null);` * * @return WebDriver The driver focused on the top window or the first frame. */ diff --git a/tests/functional/RemoteTargetLocatorTest.php b/tests/functional/RemoteTargetLocatorTest.php index e47612173..8ee5c96bc 100644 --- a/tests/functional/RemoteTargetLocatorTest.php +++ b/tests/functional/RemoteTargetLocatorTest.php @@ -77,6 +77,12 @@ public function testShouldSwitchToFrameByItsId() $this->driver->switchTo()->frame(null); $this->assertContains($parentPage, $this->driver->getPageSource()); + + $this->driver->switchTo()->frame(0); + $this->assertContains($firstChildFrame, $this->driver->getPageSource()); + + $this->driver->switchTo()->defaultContent(); + $this->assertContains($parentPage, $this->driver->getPageSource()); } public function testShouldSwitchToParentFrame() diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index 131bec2ca..f74eb754d 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -50,6 +50,21 @@ public function testShouldProvideAccessToCapabilitiesUsingSettersAndGetters() $this->assertSame(333, $capabilities->getVersion()); } + public function testShouldAccessCapabilitiesIsser() + { + $capabilities = new DesiredCapabilities(); + + $capabilities->setCapability('custom', 1337); + $capabilities->setCapability('customBooleanTrue', true); + $capabilities->setCapability('customBooleanFalse', false); + $capabilities->setCapability('customNull', null); + + $this->assertTrue($capabilities->is('custom')); + $this->assertTrue($capabilities->is('customBooleanTrue')); + $this->assertFalse($capabilities->is('customBooleanFalse')); + $this->assertFalse($capabilities->is('customNull')); + } + public function testShouldNotAllowToDisableJavascriptForNonHtmlUnitBrowser() { $this->expectException(\Exception::class); diff --git a/tests/unit/Remote/LocalFileDetectorTest.php b/tests/unit/Remote/LocalFileDetectorTest.php new file mode 100644 index 000000000..b58413d8b --- /dev/null +++ b/tests/unit/Remote/LocalFileDetectorTest.php @@ -0,0 +1,24 @@ +getLocalFile(__DIR__ . '/./' . basename(__FILE__)); + + $this->assertSame(__FILE__, $file); + } + + public function testShouldReturnNullIfFileNotDetected() + { + $detector = new LocalFileDetector(); + + $this->assertNull($detector->getLocalFile('/this/is/not/a/file')); + } +} From cfc96ebb114d16ab04ee4019b7b8358199f9ccd2 Mon Sep 17 00:00:00 2001 From: Aleksandar Rusakov Date: Wed, 5 Feb 2020 17:21:33 +0200 Subject: [PATCH 023/276] Let ZipArchive handle the creation of the zip files --- lib/Remote/RemoteWebElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 1e6a217f2..8e238698c 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -499,7 +499,7 @@ protected function upload($local_file) } // Create a temporary file in the system temp directory. - $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip'); + $temp_zip = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('WebDriverZip', false); $zip = new ZipArchive(); if (($errorCode = $zip->open($temp_zip, ZipArchive::CREATE)) !== true) { throw new WebDriverException(sprintf('Error creating zip archive: %s', $errorCode)); From e0de4572570704d8378710b0b67422ee3c333394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 7 Feb 2020 12:18:09 +0100 Subject: [PATCH 024/276] Refactor zip file upload method --- lib/Remote/RemoteWebElement.php | 38 ++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 8e238698c..fd4de3511 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -498,26 +498,38 @@ protected function upload($local_file) throw new WebDriverException('You may only upload files: ' . $local_file); } + $temp_zip_path = $this->createTemporaryZipArchive($local_file); + + $remote_path = $this->executor->execute( + DriverCommand::UPLOAD_FILE, + ['file' => base64_encode(file_get_contents($temp_zip_path))] + ); + + unlink($temp_zip_path); + + return $remote_path; + } + + /** + * @param string $fileToZip + * @return string + */ + protected function createTemporaryZipArchive($fileToZip) + { // Create a temporary file in the system temp directory. - $temp_zip = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('WebDriverZip', false); + // Intentionally do not use `tempnam()`, as it creates empty file which zip extension may not handle. + $tempZipPath = sys_get_temp_dir() . '/' . uniqid('WebDriverZip', false); + $zip = new ZipArchive(); - if (($errorCode = $zip->open($temp_zip, ZipArchive::CREATE)) !== true) { + if (($errorCode = $zip->open($tempZipPath, ZipArchive::CREATE)) !== true) { throw new WebDriverException(sprintf('Error creating zip archive: %s', $errorCode)); } - $info = pathinfo($local_file); + $info = pathinfo($fileToZip); $file_name = $info['basename']; - $zip->addFile($local_file, $file_name); + $zip->addFile($fileToZip, $file_name); $zip->close(); - $params = [ - 'file' => base64_encode(file_get_contents($temp_zip)), - ]; - $remote_path = $this->executor->execute( - DriverCommand::UPLOAD_FILE, - $params - ); - unlink($temp_zip); - return $remote_path; + return $tempZipPath; } } From 4708f6905d3daa92083b025128c770abe9d5907b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 10 Feb 2020 16:03:46 +0100 Subject: [PATCH 025/276] Add information about renaming into README (#756) --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 25d7d29de..6585cd227 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,21 @@ Then install the library: php composer.phar require php-webdriver/webdriver +## Upgrade from version <1.8.0 + +Starting from version 1.8.0, the project has been renamed from `facebook/php-webdriver` to `php-webdriver/webdriver`. + +In order to receive the new version and future updates, **you need to rename it in your composer.json**: + +```diff +"require": { +- "facebook/webdriver": "(version you use)", ++ "php-webdriver/webdriver": "(version you use)", +} +``` + +and run `composer update`. + ## Getting started ### 1. Start server (aka. remote end) From 3e33ee3b8a688d719c55acdd7c6788e3006e1d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 10 Feb 2020 16:04:25 +0100 Subject: [PATCH 026/276] =?UTF-8?q?Release=20version=201.8.0=20?= =?UTF-8?q?=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 645ffd936..7fc31a816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +## 1.8.0 - 2020-02-10 ### Added - Experimental W3C WebDriver protocol support. The protocol will be used automatically when remote end (like Geckodriver, newer Chromedriver etc.) supports it. - `getStatus()` method of `RemoteWebDriver` to get information about remote-end readiness to create new sessions. From 7729633d3b7068a62e76adc4b784eb78f8dec9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 13 Feb 2020 12:54:32 +0100 Subject: [PATCH 027/276] Fix sendKeys not accepting array as input (#759) --- CHANGELOG.md | 2 ++ lib/Remote/RemoteWebElement.php | 2 +- lib/WebDriverKeys.php | 20 +++++++++--- tests/functional/RemoteWebElementTest.php | 5 +++ tests/unit/WebDriverKeysTest.php | 39 ++++++++++++++++------- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fc31a816..48ad2ca51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Fixed +- Accept array as possible input to `sendKeys()` method. (Unintentional BC break in 1.8.0.) ## 1.8.0 - 2020-02-10 ### Added diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index fd4de3511..a02613104 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -330,7 +330,7 @@ public function sendKeys($value) if ($local_file === null) { if ($this->isW3cCompliant) { $params = [ - 'text' => (string) $value, + 'text' => WebDriverKeys::encode($value, true), ':id' => $this->id, ]; } else { diff --git a/lib/WebDriverKeys.php b/lib/WebDriverKeys.php index 77f75b4ea..5bba2eff0 100644 --- a/lib/WebDriverKeys.php +++ b/lib/WebDriverKeys.php @@ -90,11 +90,13 @@ class WebDriverKeys const COMMAND = self::META; /** - * Encode input of `sendKeys()`. + * Encode input of `sendKeys()` to appropriate format according to protocol. + * * @param string|array|int|float $keys - * @return array + * @param bool $isW3cCompliant + * @return array|string */ - public static function encode($keys) + public static function encode($keys, $isW3cCompliant = false) { if (is_numeric($keys)) { $keys = (string) $keys; @@ -105,7 +107,11 @@ public static function encode($keys) } if (!is_array($keys)) { - return []; + if (!$isW3cCompliant) { + return []; + } + + return ''; } $encoded = []; @@ -117,6 +123,10 @@ public static function encode($keys) $encoded[] = (string) $key; } - return $encoded; + if (!$isW3cCompliant) { + return $encoded; + } + + return implode('', $encoded); } } diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 46e3509bb..319a8eabb 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -157,6 +157,11 @@ public function testShouldSendKeysToFormElement() $this->assertSame('foo bar', $textarea->getAttribute('value')); $textarea->sendKeys(' baz'); $this->assertSame('foo bar baz', $textarea->getAttribute('value')); + + // Send keys as array + $textarea->clear(); + $textarea->sendKeys(['bat', 1, '3', ' ', 3, '7']); + $this->assertSame('bat13 37', $textarea->getAttribute('value')); } /** diff --git a/tests/unit/WebDriverKeysTest.php b/tests/unit/WebDriverKeysTest.php index b60bdb2b0..757b7ff99 100644 --- a/tests/unit/WebDriverKeysTest.php +++ b/tests/unit/WebDriverKeysTest.php @@ -12,11 +12,13 @@ class WebDriverKeysTest extends TestCase /** * @dataProvider provideKeys * @param mixed $keys - * @param array $expectedOutput + * @param array $expectedOssOutput + * @param string $expectedW3cOutput */ - public function testShouldEncodeKeysToArrayOfStrings($keys, $expectedOutput) + public function testShouldEncodeKeysToFormatOfEachProtocol($keys, $expectedOssOutput, $expectedW3cOutput) { - $this->assertSame($expectedOutput, WebDriverKeys::encode($keys)); + $this->assertSame($expectedOssOutput, WebDriverKeys::encode($keys)); + $this->assertSame($expectedW3cOutput, WebDriverKeys::encode($keys, true)); } /** @@ -25,19 +27,32 @@ public function testShouldEncodeKeysToArrayOfStrings($keys, $expectedOutput) public function provideKeys() { return [ - 'empty string' => ['', ['']], - 'simple string' => ['foo', ['foo']], - 'string as an array' => [['foo'], ['foo']], - 'string with modifier as an array' => [[WebDriverKeys::SHIFT, 'foo'], [WebDriverKeys::SHIFT, 'foo']], - 'string with concatenated modifier' => [[WebDriverKeys::SHIFT . 'foo'], [WebDriverKeys::SHIFT . 'foo']], - 'simple numeric value' => [3, ['3']], - 'multiple numeric values' => [[1, 3.33], ['1', '3.33']], - 'multiple mixed values ' => [['foo', WebDriverKeys::END, '1.234'], ['foo', WebDriverKeys::END, '1.234']], + 'empty string' => ['', [''], ''], + 'simple string' => ['foo', ['foo'], 'foo'], + 'string as an array' => [['foo'], ['foo'], 'foo'], + 'string with modifier as an array' => [ + [WebDriverKeys::SHIFT, 'foo'], + [WebDriverKeys::SHIFT, 'foo'], + WebDriverKeys::SHIFT . 'foo', + ], + 'string with concatenated modifier' => [ + [WebDriverKeys::SHIFT . 'foo'], + [WebDriverKeys::SHIFT . 'foo'], + WebDriverKeys::SHIFT . 'foo', + ], + 'simple numeric value' => [3, ['3'], '3'], + 'multiple numeric values' => [[1, 3.33], ['1', '3.33'], '13.33'], + 'multiple mixed values ' => [ + ['foo', WebDriverKeys::END, '1.234'], + ['foo', WebDriverKeys::END, '1.234'], + 'foo' . WebDriverKeys::END . '1.234', + ], 'array of strings with modifiers should separate them with NULL character' => [ [[WebDriverKeys::SHIFT, 'foo'], [WebDriverKeys::META, 'bar']], [WebDriverKeys::SHIFT . 'foo' . WebDriverKeys::NULL, WebDriverKeys::META . 'bar' . WebDriverKeys::NULL], + WebDriverKeys::SHIFT . 'foo' . WebDriverKeys::NULL . WebDriverKeys::META . 'bar' . WebDriverKeys::NULL, ], - 'null' => [null, []], + 'null' => [null, [], ''], ]; } } From 6ee357444f5050feac2e11aaf83cd6130931a09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 13 Feb 2020 16:30:33 +0100 Subject: [PATCH 028/276] Edge on Sauce Labs started to misidentify itself back and is failing the build --- tests/functional/RemoteWebDriverCreateTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index bf2d13620..2beaf8357 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -5,6 +5,7 @@ use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\HttpCommandExecutor; use Facebook\WebDriver\Remote\RemoteWebDriver; +use Facebook\WebDriver\Remote\WebDriverBrowserType; /** * @covers \Facebook\WebDriver\Remote\HttpCommandExecutor @@ -36,7 +37,12 @@ public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() $returnedCapabilities = $this->driver->getCapabilities(); $this->assertInstanceOf(WebDriverCapabilities::class, $returnedCapabilities); - $this->assertSame($this->desiredCapabilities->getBrowserName(), $returnedCapabilities->getBrowserName()); + + // MicrosoftEdge on Sauce Labs started to identify itself back as "msedge" + if ($this->desiredCapabilities->getBrowserName() !== WebDriverBrowserType::MICROSOFT_EDGE) { + $this->assertSame($this->desiredCapabilities->getBrowserName(), $returnedCapabilities->getBrowserName()); + } + $this->assertNotEmpty($returnedCapabilities->getPlatform()); $this->assertNotEmpty($returnedCapabilities); $this->assertNotEmpty($returnedCapabilities->getVersion()); From e8c0f60e0ed9d639d7e40c5bbefe7786c26694bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 12 Feb 2020 01:27:50 +0100 Subject: [PATCH 029/276] Use constants when referencing mouse buttons --- lib/Remote/RemoteMouse.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index e95a12fe3..2d9c34a99 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -10,6 +10,13 @@ */ class RemoteMouse implements WebDriverMouse { + /** @internal */ + const BUTTON_LEFT = 0; + /** @internal */ + const BUTTON_MIDDLE = 1; + /** @internal */ + const BUTTON_RIGHT = 2; + /** * @var RemoteExecuteMethod */ @@ -54,7 +61,7 @@ public function click(WebDriverCoordinates $where = null) $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::CLICK, [ - 'button' => 0, + 'button' => self::BUTTON_LEFT, ]); return $this; @@ -78,13 +85,11 @@ public function contextClick(WebDriverCoordinates $where = null) 'actions' => array_merge($moveAction, [ [ 'type' => 'pointerDown', - 'duration' => 0, - 'button' => 2, + 'button' => self::BUTTON_RIGHT, ], [ 'type' => 'pointerUp', - 'duration' => 0, - 'button' => 2, + 'button' => self::BUTTON_RIGHT, ], ]), ], @@ -96,7 +101,7 @@ public function contextClick(WebDriverCoordinates $where = null) $this->moveIfNeeded($where); $this->executor->execute(DriverCommand::CLICK, [ - 'button' => 2, + 'button' => self::BUTTON_RIGHT, ]); return $this; @@ -150,8 +155,7 @@ public function mouseDown(WebDriverCoordinates $where = null) $this->createMoveAction($where), [ 'type' => 'pointerDown', - 'duration' => 0, - 'button' => 0, + 'button' => self::BUTTON_LEFT, ], ], ], @@ -229,8 +233,7 @@ public function mouseUp(WebDriverCoordinates $where = null) 'actions' => array_merge($moveAction, [ [ 'type' => 'pointerUp', - 'duration' => 0, - 'button' => 0, + 'button' => self::BUTTON_LEFT, ], ]), ], @@ -290,13 +293,11 @@ private function createClickActions() return [ [ 'type' => 'pointerDown', - 'duration' => 0, - 'button' => 0, + 'button' => self::BUTTON_LEFT, ], [ 'type' => 'pointerUp', - 'duration' => 0, - 'button' => 0, + 'button' => self::BUTTON_LEFT, ], ]; } From f6fe710c7160d3058016f3caf66a9a7fef61f36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 13 Feb 2020 14:36:22 +0100 Subject: [PATCH 030/276] Add functional tests for dragAndDrop actions --- tests/functional/WebDriverActionsTest.php | 134 ++++++++++++++++------ tests/functional/web/events.html | 2 + tests/functional/web/index.html | 2 + tests/functional/web/sortable.html | 76 ++++++++++++ 4 files changed, 177 insertions(+), 37 deletions(-) create mode 100644 tests/functional/web/sortable.html diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 054147d52..40c560f96 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -5,28 +5,32 @@ use Facebook\WebDriver\Remote\WebDriverBrowserType; /** - * @coversDefaultClass \Facebook\WebDriver\Interactions\WebDriverActions + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverButtonReleaseAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverClickAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverContextClickAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverKeysRelatedAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverKeyUpAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverMouseAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction + * @covers \Facebook\WebDriver\Interactions\Internal\WebDriverSingleKeyAction + * @covers \Facebook\WebDriver\Interactions\WebDriverActions */ class WebDriverActionsTest extends WebDriverTestCase { - protected function setUp() - { - parent::setUp(); - - $this->driver->get($this->getTestPageUrl('events.html')); - } - - /** - * @covers ::__construct - * @covers ::click - * @covers ::perform - */ public function testShouldClickOnElement() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { $this->markTestSkipped('Not supported by HtmlUnit browser'); } + $this->driver->get($this->getTestPageUrl('events.html')); + $element = $this->driver->findElement(WebDriverBy::id('item-1')); $this->driver->action() @@ -45,18 +49,14 @@ public function testShouldClickOnElement() $this->assertSame($logs, $loggedEvents); } - /** - * @covers ::__construct - * @covers ::clickAndHold - * @covers ::perform - * @covers ::release - */ public function testShouldClickAndHoldOnElementAndRelease() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { $this->markTestSkipped('Not supported by HtmlUnit browser'); } + $this->driver->get($this->getTestPageUrl('events.html')); + $element = $this->driver->findElement(WebDriverBy::id('item-1')); $this->driver->action() @@ -76,9 +76,6 @@ public function testShouldClickAndHoldOnElementAndRelease() /** * @group exclude-saucelabs - * @covers ::__construct - * @covers ::contextClick - * @covers ::perform */ public function testShouldContextClickOnElement() { @@ -90,6 +87,8 @@ public function testShouldContextClickOnElement() $this->markTestSkipped('Getting stuck in EdgeDriver'); } + $this->driver->get($this->getTestPageUrl('events.html')); + $element = $this->driver->findElement(WebDriverBy::id('item-2')); $this->driver->action() @@ -103,17 +102,14 @@ public function testShouldContextClickOnElement() $this->assertContains('contextmenu item-2', $loggedEvents); } - /** - * @covers ::__construct - * @covers ::doubleClick - * @covers ::perform - */ public function testShouldDoubleClickOnElement() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { $this->markTestSkipped('Not supported by HtmlUnit browser'); } + $this->driver->get($this->getTestPageUrl('events.html')); + $element = $this->driver->findElement(WebDriverBy::id('item-3')); $this->driver->action() @@ -124,9 +120,6 @@ public function testShouldDoubleClickOnElement() } /** - * @covers ::__construct - * @covers ::dragAndDrop - * @covers ::perform * @group exclude-saucelabs */ public function testShouldDragAndDrop() @@ -135,17 +128,70 @@ public function testShouldDragAndDrop() $this->markTestSkipped('Not supported by HtmlUnit browser'); } - $element = $this->driver->findElement(WebDriverBy::id('item-3')); - $target = $this->driver->findElement(WebDriverBy::id('item-1')); + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::FIREFOX) { + self::skipForJsonWireProtocol('Broken in legacy Firefox'); + } + + $this->driver->get($this->getTestPageUrl('sortable.html')); + + $item13 = $this->driver->findElement(WebDriverBy::id('item-1-3')); + $item24 = $this->driver->findElement(WebDriverBy::id('item-2-4')); + + $this->driver->action() + ->dragAndDrop($item13, $item24) + ->perform(); + + $this->assertSame( + [['1-1', '1-2', '1-4', '1-5'], ['2-1', '2-2', '2-3', '2-4', '1-3', '2-5']], + $this->retrieveListContent() + ); + + $item21 = $this->driver->findElement(WebDriverBy::id('item-2-1')); $this->driver->action() - ->dragAndDrop($element, $target) + ->dragAndDrop($item24, $item21) ->perform(); - $this->assertContains('mouseover item-3', $this->retrieveLoggedEvents()); - $this->assertContains('mousedown item-3', $this->retrieveLoggedEvents()); - $this->assertContains('mouseover item-1', $this->retrieveLoggedEvents()); - $this->assertContains('mouseup item-1', $this->retrieveLoggedEvents()); + $this->assertSame( + [['1-1', '1-2', '1-4', '1-5'], ['2-4', '2-1', '2-2', '2-3', '1-3', '2-5']], + $this->retrieveListContent() + ); + } + + /** + * @group exclude-saucelabs + */ + public function testShouldDragAndDropBy() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $this->driver->get($this->getTestPageUrl('sortable.html')); + + $item13 = $this->driver->findElement(WebDriverBy::id('item-1-3')); + + $this->driver->action() + ->dragAndDropBy($item13, 100, 55) + ->perform(); + + $this->assertSame( + [['1-1', '1-2', '1-4', '1-5'], ['2-1', '2-2', '2-3', '2-4', '1-3', '2-5']], + $this->retrieveListContent() + ); + + $item25 = $this->driver->findElement(WebDriverBy::id('item-2-5')); + $item22 = $this->driver->findElement(WebDriverBy::id('item-2-2')); + + $this->driver->action() + ->dragAndDropBy($item25, 0, -130) + ->dragAndDropBy($item22, -100, -35) + ->perform(); + + $this->assertSame( + [['1-1', '2-2', '1-2', '1-4', '1-5'], ['2-1', '2-5', '2-3', '2-4', '1-3']], + $this->retrieveListContent() + ); } /** @@ -157,4 +203,18 @@ private function retrieveLoggedEvents() return explode("\n", $logElement->getText()); } + + /** + * @return array + */ + private function retrieveListContent() + { + $list1 = $this->driver->findElement(WebDriverBy::cssSelector('#sortable1')); + $list2 = $this->driver->findElement(WebDriverBy::cssSelector('#sortable2')); + + return [ + explode("\n", $list1->getText()), + explode("\n", $list2->getText()), + ]; + } } diff --git a/tests/functional/web/events.html b/tests/functional/web/events.html index 45e8f3971..5511d321a 100644 --- a/tests/functional/web/events.html +++ b/tests/functional/web/events.html @@ -28,8 +28,10 @@
  • Third item
  • +

    Mouse events:

    
     
    +

    Keyboard events:

    
     
     
    +    
    +    
    +
    +
    +
    +

    Sortable using jQuery

    + + +
    +
    +
      +
    • 1-1
    • +
    • 1-2
    • +
    • 1-3
    • +
    • 1-4
    • +
    • 1-5
    • +
    +
    +
    +
      +
    • 2-1
    • +
    • 2-2
    • +
    • 2-3
    • +
    • 2-4
    • +
    • 2-5
    • +
    +
    +
    + + + From 7f8382892cb34118700c8544e4a03366efbcc50f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 12 Feb 2020 01:41:52 +0100 Subject: [PATCH 031/276] Fix mouse move action in W3C mode to use relative offset (fixes #757) https://w3c.github.io/webdriver/#dfn-dispatch-a-pointermove-action --- CHANGELOG.md | 1 + lib/Remote/RemoteMouse.php | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48ad2ca51..c62e52d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased ### Fixed - Accept array as possible input to `sendKeys()` method. (Unintentional BC break in 1.8.0.) +- Use relative offset when moving mouse pointer in W3C WebDriver mode. ## 1.8.0 - 2020-02-10 ### Added diff --git a/lib/Remote/RemoteMouse.php b/lib/Remote/RemoteMouse.php index 2d9c34a99..3495ea745 100644 --- a/lib/Remote/RemoteMouse.php +++ b/lib/Remote/RemoteMouse.php @@ -273,13 +273,15 @@ private function createMoveAction( ) { $move_action = [ 'type' => 'pointerMove', - 'duration' => 0, + 'duration' => 100, // to simulate human delay 'x' => $x_offset === null ? 0 : $x_offset, 'y' => $y_offset === null ? 0 : $y_offset, ]; if ($where !== null) { $move_action['origin'] = [JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER => $where->getAuxiliary()]; + } else { + $move_action['origin'] = 'pointer'; } return $move_action; From 739d2fc13787f810f7bcf9d54428a44b91eee9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 13 Feb 2020 15:25:08 +0100 Subject: [PATCH 032/276] Add functional tests for keys actions --- lib/Interactions/WebDriverActions.php | 2 +- tests/functional/RemoteKeyboardTest.php | 16 +--- tests/functional/RetrieveEventsTrait.php | 31 +++++++ tests/functional/WebDriverActionsTest.php | 106 +++++++++++++++++----- 4 files changed, 121 insertions(+), 34 deletions(-) create mode 100644 tests/functional/RetrieveEventsTrait.php diff --git a/lib/Interactions/WebDriverActions.php b/lib/Interactions/WebDriverActions.php index aefd07faf..b5172e2e7 100644 --- a/lib/Interactions/WebDriverActions.php +++ b/lib/Interactions/WebDriverActions.php @@ -245,7 +245,7 @@ public function keyUp(WebDriverElement $element = null, $key = null) /** * Send keys by keyboard. - * If $element is provided, focus on that element first. + * If $element is provided, focus on that element first (using single mouse click). * * @see WebDriverKeys for special keys like CONTROL, ALT, etc. * @param WebDriverElement $element diff --git a/tests/functional/RemoteKeyboardTest.php b/tests/functional/RemoteKeyboardTest.php index 3da1341c0..45c9be151 100644 --- a/tests/functional/RemoteKeyboardTest.php +++ b/tests/functional/RemoteKeyboardTest.php @@ -9,6 +9,8 @@ */ class RemoteKeyboardTest extends WebDriverTestCase { + use RetrieveEventsTrait; + /** * @group exclude-firefox * Firefox does not properly support keyboard actions: @@ -55,7 +57,7 @@ public function testShouldPressSendAndReleaseKeys() 'keyup "Shift"', 'keyup "f"', ], - $this->retrieveLoggedEvents() + $this->retrieveLoggedKeyboardEvents() ); } else { $this->assertEquals( @@ -79,18 +81,8 @@ public function testShouldPressSendAndReleaseKeys() 'keydown "f"', 'keyup "f"', ], - $this->retrieveLoggedEvents() + $this->retrieveLoggedKeyboardEvents() ); } } - - /** - * @return array - */ - private function retrieveLoggedEvents() - { - $logElement = $this->driver->findElement(WebDriverBy::id('keyboardEventsLog')); - - return explode("\n", $logElement->getText()); - } } diff --git a/tests/functional/RetrieveEventsTrait.php b/tests/functional/RetrieveEventsTrait.php new file mode 100644 index 000000000..3a4a3d512 --- /dev/null +++ b/tests/functional/RetrieveEventsTrait.php @@ -0,0 +1,31 @@ +driver->findElement(WebDriverBy::id('keyboardEventsLog')); + + return explode("\n", $logElement->getText()); + } + + /** + * @return array + */ + private function retrieveLoggedMouseEvents() + { + $logElement = $this->driver->findElement(WebDriverBy::id('mouseEventsLog')); + + return explode("\n", $logElement->getText()); + } +} diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 40c560f96..476b359fd 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -23,6 +23,8 @@ */ class WebDriverActionsTest extends WebDriverTestCase { + use RetrieveEventsTrait; + public function testShouldClickOnElement() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { @@ -38,7 +40,7 @@ public function testShouldClickOnElement() ->perform(); $logs = ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1']; - $loggedEvents = $this->retrieveLoggedEvents(); + $loggedEvents = $this->retrieveLoggedMouseEvents(); if (getenv('GECKODRIVER') === '1') { $loggedEvents = array_slice($loggedEvents, 0, count($logs)); @@ -65,11 +67,11 @@ public function testShouldClickAndHoldOnElementAndRelease() ->perform(); if (self::isW3cProtocolBuild()) { - $this->assertArraySubset(['mouseover item-1', 'mousedown item-1'], $this->retrieveLoggedEvents()); + $this->assertArraySubset(['mouseover item-1', 'mousedown item-1'], $this->retrieveLoggedMouseEvents()); } else { $this->assertSame( ['mouseover item-1', 'mousedown item-1', 'mouseup item-1', 'click item-1'], - $this->retrieveLoggedEvents() + $this->retrieveLoggedMouseEvents() ); } } @@ -95,7 +97,7 @@ public function testShouldContextClickOnElement() ->contextClick($element) ->perform(); - $loggedEvents = $this->retrieveLoggedEvents(); + $loggedEvents = $this->retrieveLoggedMouseEvents(); $this->assertContains('mousedown item-2', $loggedEvents); $this->assertContains('mouseup item-2', $loggedEvents); @@ -116,12 +118,87 @@ public function testShouldDoubleClickOnElement() ->doubleClick($element) ->perform(); - $this->assertContains('dblclick item-3', $this->retrieveLoggedEvents()); + $this->assertContains('dblclick item-3', $this->retrieveLoggedMouseEvents()); + } + + public function testShouldSendKeysUpAndDown() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::FIREFOX) { + self::skipForJsonWireProtocol('Broken in legacy Firefox'); + } + + $this->driver->get($this->getTestPageUrl('events.html')); + + $this->driver->action() + ->keyDown(null, WebDriverKeys::CONTROL) + ->keyUp(null, WebDriverKeys::CONTROL) + ->sendKeys(null, 'ab') + ->perform(); + + $events = $this->retrieveLoggedKeyboardEvents(); + + $this->assertEquals( + [ + 'keydown "Control"', + 'keyup "Control"', + 'keydown "a"', + 'keyup "a"', + 'keydown "b"', + 'keyup "b"', + ], + $events + ); + } + + public function testShouldMoveToElement() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $this->driver->get($this->getTestPageUrl('sortable.html')); + + $item13 = $this->driver->findElement(WebDriverBy::id('item-1-3')); + $item24 = $this->driver->findElement(WebDriverBy::id('item-2-4')); + + $this->driver->action() + ->clickAndHold($item13) + ->moveToElement($item24) + ->release() + ->perform(); + + $this->assertSame( + [['1-1', '1-2', '1-4', '1-5'], ['2-1', '2-2', '2-3', '2-4', '1-3', '2-5']], + $this->retrieveListContent() + ); + } + + public function testShouldMoveByOffset() + { + if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { + $this->markTestSkipped('Not supported by HtmlUnit browser'); + } + + $this->driver->get($this->getTestPageUrl('sortable.html')); + + $item13 = $this->driver->findElement(WebDriverBy::id('item-1-3')); + + $this->driver->action() + ->clickAndHold($item13) + ->moveByOffset(100, 55) + ->release() + ->perform(); + + $this->assertSame( + [['1-1', '1-2', '1-4', '1-5'], ['2-1', '2-2', '2-3', '2-4', '1-3', '2-5']], + $this->retrieveListContent() + ); } - /** - * @group exclude-saucelabs - */ public function testShouldDragAndDrop() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { @@ -158,9 +235,6 @@ public function testShouldDragAndDrop() ); } - /** - * @group exclude-saucelabs - */ public function testShouldDragAndDropBy() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { @@ -194,16 +268,6 @@ public function testShouldDragAndDropBy() ); } - /** - * @return array - */ - private function retrieveLoggedEvents() - { - $logElement = $this->driver->findElement(WebDriverBy::id('mouseEventsLog')); - - return explode("\n", $logElement->getText()); - } - /** * @return array */ From 639cb48fbc575f73d73c3b02eb3c2512052caebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sun, 16 Feb 2020 20:10:27 +0100 Subject: [PATCH 033/276] Exclude skipped tests on SauceLabs --- tests/functional/WebDriverActionsTest.php | 6 ++++++ tests/functional/WebDriverWindowTest.php | 1 + 2 files changed, 7 insertions(+) diff --git a/tests/functional/WebDriverActionsTest.php b/tests/functional/WebDriverActionsTest.php index 476b359fd..c3909da9b 100644 --- a/tests/functional/WebDriverActionsTest.php +++ b/tests/functional/WebDriverActionsTest.php @@ -121,6 +121,9 @@ public function testShouldDoubleClickOnElement() $this->assertContains('dblclick item-3', $this->retrieveLoggedMouseEvents()); } + /** + * @group exclude-saucelabs + */ public function testShouldSendKeysUpAndDown() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { @@ -199,6 +202,9 @@ public function testShouldMoveByOffset() ); } + /** + * @group exclude-saucelabs + */ public function testShouldDragAndDrop() { if ($this->desiredCapabilities->getBrowserName() === WebDriverBrowserType::HTMLUNIT) { diff --git a/tests/functional/WebDriverWindowTest.php b/tests/functional/WebDriverWindowTest.php index ba0b45187..62756f847 100644 --- a/tests/functional/WebDriverWindowTest.php +++ b/tests/functional/WebDriverWindowTest.php @@ -49,6 +49,7 @@ public function testShouldMaximizeWindow() } /** + * @group exclude-saucelabs * @group exclude-edge * @group exclude-chrome * @see https://bugs.chromium.org/p/chromium/issues/detail?id=1049336 From 4c4bae3eaa1a474db8bc2d36b673d1e1681cb9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Feb 2020 22:31:22 +0100 Subject: [PATCH 034/276] Reference phpunit.xsd from vendor to make it always up-to-date --- phpunit.xml.dist | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 430a8fb5c..2e81aef6d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,15 +3,9 @@ From 073a170b8b5f337c2b4eebf00057d346887e5697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 14 Feb 2020 22:31:33 +0100 Subject: [PATCH 035/276] Normalize composer.json --- .github/workflows/php.yaml | 8 +++++- composer.json | 53 +++++++++++++++++++++++--------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml index 04fd5b9da..c96bec74e 100644 --- a/.github/workflows/php.yaml +++ b/.github/workflows/php.yaml @@ -22,7 +22,13 @@ jobs: - name: Install dependencies run: | composer update --no-interaction - composer require phpstan/phpstan # Not part of require-dev, because it won't install on PHP 5.6 + composer require --dev phpstan/phpstan # Not part of require-dev, because it won't install on PHP 5.6 + composer require --dev ergebnis/composer-normalize + + - name: Check composer.json + run: | + composer validate --strict + composer normalize --dry-run - name: Run checks run: | diff --git a/composer.json b/composer.json index 77df01f21..619ebc205 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,16 @@ { "name": "php-webdriver/webdriver", + "type": "library", "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.", - "keywords": ["webdriver", "selenium", "php", "geckodriver", "chromedriver"], + "keywords": [ + "webdriver", + "selenium", + "php", + "geckodriver", + "chromedriver" + ], "homepage": "https://github.com/php-webdriver/php-webdriver", - "type": "library", "license": "MIT", - "minimum-stability": "beta", "require": { "php": "^5.6 || ~7.0", "ext-curl": "*", @@ -28,21 +33,39 @@ "suggest": { "ext-SimpleXML": "For Firefox profile creation" }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, "autoload": { - "files": [ - "lib/Exception/TimeoutException.php" - ], "psr-4": { "Facebook\\WebDriver\\": "lib/" - } + }, + "files": [ + "lib/Exception/TimeoutException.php" + ] }, "autoload-dev": { "psr-4": { - "Facebook\\WebDriver\\": ["tests/unit", "tests/functional"] + "Facebook\\WebDriver\\": [ + "tests/unit", + "tests/functional" + ] }, - "classmap": ["tests/functional/"] + "classmap": [ + "tests/functional/" + ] }, + "minimum-stability": "beta", "scripts": { + "analyze": [ + "vendor/bin/parallel-lint -j 10 ./lib ./tests example.php", + "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi" + ], "codestyle:check": [ "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff --dry-run -vvv --ansi", "vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/" @@ -50,18 +73,6 @@ "codestyle:fix": [ "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff -vvv || exit 0", "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/" - ], - "analyze": [ - "vendor/bin/parallel-lint -j 10 ./lib ./tests example.php", - "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi" ] - }, - "config": { - "sort-packages": true - }, - "extra": { - "branch-alias": { - "dev-master": "1.8.x-dev" - } } } From 262ea0d209c292e0330be1041424887bbbffef04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 17 Feb 2020 09:14:38 +0100 Subject: [PATCH 036/276] Release version 1.8.1 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c62e52d87..9c5d381ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.8.1 - 2020-02-17 ### Fixed - Accept array as possible input to `sendKeys()` method. (Unintentional BC break in 1.8.0.) - Use relative offset when moving mouse pointer in W3C WebDriver mode. From cfb919b93e665b8e07a60ddec89a5a942819a84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 19 Feb 2020 12:03:11 +0100 Subject: [PATCH 037/276] Reimplement element equals method for W3C mode --- CHANGELOG.md | 2 ++ lib/Remote/RemoteWebElement.php | 3 +-- tests/functional/RemoteWebElementTest.php | 3 --- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c5d381ad..9b0cbc84e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Changed +- Reimplement element `equals()` method to be working in W3C mode. ## 1.8.1 - 2020-02-17 ### Fixed diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index a02613104..023a7390c 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -2,7 +2,6 @@ namespace Facebook\WebDriver\Remote; -use Facebook\WebDriver\Exception\UnsupportedOperationException; use Facebook\WebDriver\Exception\WebDriverException; use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates; use Facebook\WebDriver\Internal\WebDriverLocatable; @@ -463,7 +462,7 @@ public function takeElementScreenshot($save_as = null) public function equals(WebDriverElement $other) { if ($this->isW3cCompliant) { - throw new UnsupportedOperationException('"elementEquals" is not supported by the W3C specification'); + return $this->getID() === $other->getID(); } return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, [ diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 319a8eabb..cacf16390 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -262,12 +262,9 @@ public function testShouldSubmitFormByClickOnSubmitInput() /** * @covers ::equals - * @group exclude-saucelabs */ public function testShouldCompareEqualsElement() { - self::skipForW3cProtocol('"equals" is not supported by the W3C specification'); - $this->driver->get($this->getTestPageUrl('index.html')); $firstElement = $this->driver->findElement(WebDriverBy::cssSelector('ul.list')); From fdf430d33376acf626b6335ecf576f7c3d7a5e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 24 Feb 2020 17:54:33 +0100 Subject: [PATCH 038/276] When creating from session ID properly read W3C compliance param --- CHANGELOG.md | 3 +++ lib/Remote/RemoteWebDriver.php | 10 ++++++++-- phpstan.neon | 4 ++++ tests/functional/RemoteWebDriverCreateTest.php | 6 +++++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b0cbc84e..95cf82f88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Changed - Reimplement element `equals()` method to be working in W3C mode. +### Fixed +- Properly read fifth parameter whether W3C compliant instance should be created when using `createBySessionID()`. + ## 1.8.1 - 2020-02-17 ### Fixed - Accept array as possible input to `sendKeys()` method. (Unintentional BC break in 1.8.0.) diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index f157fdf06..0f81a2f90 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -161,6 +161,7 @@ public static function create( * @param string $session_id The existing session id * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server + * @param bool $isW3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec * @return static */ public static function createBySessionID( @@ -170,7 +171,8 @@ public static function createBySessionID( $request_timeout_in_ms = null ) { // BC layer to not break the method signature - $w3c_compliant = func_num_args() > 3 ? func_get_arg(3) : false; + $isW3cCompliant = func_num_args() > 4 ? func_get_arg(4) : false; + $executor = new HttpCommandExecutor($selenium_server_url, null, null); if ($connection_timeout_in_ms !== null) { $executor->setConnectionTimeout($connection_timeout_in_ms); @@ -179,7 +181,11 @@ public static function createBySessionID( $executor->setRequestTimeout($request_timeout_in_ms); } - return new static($executor, $session_id, null, $w3c_compliant); + if (!$isW3cCompliant) { + $executor->disableW3cCompliance(); + } + + return new static($executor, $session_id, null, $isW3cCompliant); } /** diff --git a/phpstan.neon b/phpstan.neon index de6574f0b..cf3300bfe 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -10,4 +10,8 @@ parameters: - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::equals\(\)#' - '#Unsafe usage of new static\(\)#' + # Parameter is intentionally not part of signature to not break BC + - message: '#PHPDoc tag \@param references unknown parameter: \$isW3cCompliant#' + path: 'lib/Remote/RemoteWebDriver.php' + inferPrivatePropertyTypeFromConstructor: true diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 2beaf8357..4eb7ee507 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -92,11 +92,15 @@ public function testShouldCreateInstanceFromExistingSessionId() // Store session ID $sessionId = $originalDriver->getSessionID(); + $isW3cCompliant = $originalDriver->isW3cCompliant(); // Create new RemoteWebDriver instance based on the session ID - $this->driver = RemoteWebDriver::createBySessionID($sessionId, $this->serverUrl); + $this->driver = RemoteWebDriver::createBySessionID($sessionId, $this->serverUrl, null, null, $isW3cCompliant); // Check we reused the previous instance (window) and it has the same URL $this->assertContains('/index.html', $this->driver->getCurrentURL()); + + // Do some interaction with the new driver + $this->assertNotEmpty($this->driver->findElement(WebDriverBy::id('id_test'))->getText()); } } From c1539255983f567d7711641ce603e9a3e4d13563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 24 Feb 2020 17:56:58 +0100 Subject: [PATCH 039/276] Create W3C compatible instance by default (fixes #771) --- CHANGELOG.md | 1 + lib/Remote/RemoteWebDriver.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95cf82f88..128ee4b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased ### Changed - Reimplement element `equals()` method to be working in W3C mode. +- New instance of `RemoteWebDriver` created via `createBySessionID()` by default expects W3C mode. This could be disabled using fifth parameter of `createBySessionID()`. ### Fixed - Properly read fifth parameter whether W3C compliant instance should be created when using `createBySessionID()`. diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index 0f81a2f90..b5f53246f 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -161,7 +161,7 @@ public static function create( * @param string $session_id The existing session id * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server - * @param bool $isW3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec + * @param bool $isW3cCompliant True to use W3C WebDriver (default), false to use the legacy JsonWire protocol * @return static */ public static function createBySessionID( @@ -171,7 +171,7 @@ public static function createBySessionID( $request_timeout_in_ms = null ) { // BC layer to not break the method signature - $isW3cCompliant = func_num_args() > 4 ? func_get_arg(4) : false; + $isW3cCompliant = func_num_args() > 4 ? func_get_arg(4) : true; $executor = new HttpCommandExecutor($selenium_server_url, null, null); if ($connection_timeout_in_ms !== null) { From b614a01496ad7efe21bc24dc63c6419ebbf76eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 22 Feb 2020 12:16:36 +0100 Subject: [PATCH 040/276] Fix creating firefox profile zip when using libzip 1.6+ --- lib/Firefox/FirefoxProfile.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Firefox/FirefoxProfile.php b/lib/Firefox/FirefoxProfile.php index 04e31dbc0..cce9baaf4 100644 --- a/lib/Firefox/FirefoxProfile.php +++ b/lib/Firefox/FirefoxProfile.php @@ -148,8 +148,10 @@ public function encode() } file_put_contents($temp_dir . '/user.js', $content); + // Intentionally do not use `tempnam()`, as it creates empty file which zip extension may not handle. + $temp_zip = sys_get_temp_dir() . '/' . uniqid('WebDriverFirefoxProfileZip', false); + $zip = new ZipArchive(); - $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverFirefoxProfileZip'); $zip->open($temp_zip, ZipArchive::CREATE); $dir = new RecursiveDirectoryIterator($temp_dir); From 792e82cfb90375efb9191e487ab260fa193cf39c Mon Sep 17 00:00:00 2001 From: Chin Leung Date: Mon, 17 Feb 2020 10:17:23 -0500 Subject: [PATCH 041/276] Disable the JSON viewer in Firefox --- lib/Firefox/FirefoxPreferences.php | 2 ++ lib/Remote/DesiredCapabilities.php | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Firefox/FirefoxPreferences.php b/lib/Firefox/FirefoxPreferences.php index 96248aa98..159a9c806 100644 --- a/lib/Firefox/FirefoxPreferences.php +++ b/lib/Firefox/FirefoxPreferences.php @@ -16,6 +16,8 @@ class FirefoxPreferences const READER_PARSE_ON_LOAD_ENABLED = 'reader.parse-on-load.enabled'; /** @var string Browser homepage */ const BROWSER_STARTUP_HOMEPAGE = 'browser.startup.homepage'; + /** @var string Should the Devtools JSON view be enabled? */ + const DEVTOOLS_JSONVIEW = 'devtools.jsonview.enabled'; private function __construct() { diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index 7eef1de29..e022ccecd 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -288,9 +288,12 @@ public static function firefox() WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, ]); - // disable the "Reader View" help tooltip, which can hide elements in the window.document $profile = new FirefoxProfile(); + // disable the "Reader View" help tooltip, which can hide elements in the window.document $profile->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false); + // disable JSON viewer and let JSON be rendered as raw data + $profile->setPreference(FirefoxPreferences::DEVTOOLS_JSONVIEW, false); + $caps->setCapability(FirefoxDriver::PROFILE, $profile); return $caps; From 28fdc8db48b186817d4b9fbf86d7e6853e6b0609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 4 Mar 2020 13:17:19 +0100 Subject: [PATCH 042/276] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 128ee4b78..71d904027 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,11 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Changed - Reimplement element `equals()` method to be working in W3C mode. - New instance of `RemoteWebDriver` created via `createBySessionID()` by default expects W3C mode. This could be disabled using fifth parameter of `createBySessionID()`. +- Disable JSON viewer in Firefox to let JSON response be rendered as-is. ### Fixed - Properly read fifth parameter whether W3C compliant instance should be created when using `createBySessionID()`. +- Creating of Firefox profile with libzip 1.6+ (eg. on Mac OS Catalina). ## 1.8.1 - 2020-02-17 ### Fixed From 3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 4 Mar 2020 15:40:12 +0100 Subject: [PATCH 043/276] Release version 1.8.2 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d904027..b2ff306a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.8.2 - 2020-03-04 ### Changed - Reimplement element `equals()` method to be working in W3C mode. - New instance of `RemoteWebDriver` created via `createBySessionID()` by default expects W3C mode. This could be disabled using fifth parameter of `createBySessionID()`. From 306402134d01590dad2070b779288e30b7fce5ea Mon Sep 17 00:00:00 2001 From: William Desportes Date: Thu, 19 Mar 2020 21:47:38 +0100 Subject: [PATCH 044/276] Clean up some files from dist version --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitattributes b/.gitattributes index c3b6383af..3123b82f2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,7 @@ /.travis.yml export-ignore /example.php export-ignore /phpunit.xml.dist export-ignore +/.github export-ignore +/.php_cs.dist export-ignore +/phpstan.neon export-ignore +/.coveralls.yml export-ignore From 512899069b78274b4f09d96f209b788603faaf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 24 Apr 2020 16:34:08 +0200 Subject: [PATCH 045/276] Update dependencies and fix phpstan build --- composer.json | 2 +- phpstan.neon | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 619ebc205..1d6e43ec0 100644 --- a/composer.json +++ b/composer.json @@ -21,9 +21,9 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", - "jakub-onderka/php-parallel-lint": "^1.0", "php-coveralls/php-coveralls": "^2.0", "php-mock/php-mock-phpunit": "^1.1", + "php-parallel-lint/php-parallel-lint": "^1.2", "phpunit/phpunit": "^5.7", "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", "sminnee/phpunit-mock-objects": "^3.4", diff --git a/phpstan.neon b/phpstan.neon index cf3300bfe..939659c07 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,5 @@ parameters: ignoreErrors: - - '#Class Symfony\\Component\\Process\\ProcessBuilder not found.#' - - '#Instantiated class Symfony\\Component\\Process\\ProcessBuilder not found.#' - - '#Call to method setPrefix\(\) on an unknown class Symfony\\Component\\Process\\ProcessBuilder#' # To be fixed: - '#Call to an undefined method RecursiveIteratorIterator::getSubPathName\(\)#' - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#' From 86179ee11f5d8a2ad07ac837b06122aad9449cf7 Mon Sep 17 00:00:00 2001 From: Jean Ragouin Date: Sun, 12 Apr 2020 21:45:07 +0800 Subject: [PATCH 046/276] Update method description --- lib/Remote/RemoteWebElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 023a7390c..f8ee1d1fd 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -124,7 +124,7 @@ public function findElements(WebDriverBy $by) } /** - * Get the value of a the given attribute of the element. + * Get the value of the given attribute of the element. * * @param string $attribute_name The name of the attribute. * @return string|null The value of the attribute. From a3b6811dcf3d638ddcd33cf82cc81fd2d334d7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Fri, 24 Apr 2020 18:31:12 +0200 Subject: [PATCH 047/276] Mark package replacing facebook/webdriver (fixes #780) --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 1d6e43ec0..32014e38c 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,9 @@ "symfony/polyfill-mbstring": "^1.12", "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0" }, + "replace": { + "facebook/webdriver": "*" + }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", "php-coveralls/php-coveralls": "^2.0", From f5caf908489c4b2ba0b8b378e1d2b7487e33b116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 7 May 2020 00:35:03 +0200 Subject: [PATCH 048/276] Fix phpstan build --- phpstan.neon | 1 - 1 file changed, 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index 939659c07..b0777e2c2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,6 @@ parameters: ignoreErrors: # To be fixed: - - '#Call to an undefined method RecursiveIteratorIterator::getSubPathName\(\)#' - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#' - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::getCoordinates\(\)#' - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::equals\(\)#' From a5974811f645adf625c27af8abd7e8a73e89a362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 9 May 2020 12:33:26 +0200 Subject: [PATCH 049/276] Fix alertIsPresent expected condition in W3C mode (fixes #790) --- lib/WebDriverExpectedCondition.php | 4 ++-- tests/functional/WebDriverAlertTest.php | 4 ++-- tests/functional/web/alert.html | 11 ++++++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/WebDriverExpectedCondition.php b/lib/WebDriverExpectedCondition.php index 23fc92fba..02d2e71e0 100644 --- a/lib/WebDriverExpectedCondition.php +++ b/lib/WebDriverExpectedCondition.php @@ -2,7 +2,7 @@ namespace Facebook\WebDriver; -use Facebook\WebDriver\Exception\NoAlertOpenException; +use Facebook\WebDriver\Exception\NoSuchAlertException; use Facebook\WebDriver\Exception\NoSuchElementException; use Facebook\WebDriver\Exception\NoSuchFrameException; use Facebook\WebDriver\Exception\StaleElementReferenceException; @@ -545,7 +545,7 @@ function (WebDriver $driver) { $alert->getText(); return $alert; - } catch (NoAlertOpenException $e) { + } catch (NoSuchAlertException $e) { return null; } } diff --git a/tests/functional/WebDriverAlertTest.php b/tests/functional/WebDriverAlertTest.php index 83730f6af..f8373d635 100644 --- a/tests/functional/WebDriverAlertTest.php +++ b/tests/functional/WebDriverAlertTest.php @@ -21,8 +21,8 @@ protected function setUp() public function testShouldAcceptAlert() { - // Open alert - $this->driver->findElement(WebDriverBy::id('open-alert'))->click(); + // Open alert (it is delayed for 1 second, to make sure following wait for alertIsPresent works properly) + $this->driver->findElement(WebDriverBy::id('open-alert-delayed'))->click(); // Wait until present $this->driver->wait()->until(WebDriverExpectedCondition::alertIsPresent()); diff --git a/tests/functional/web/alert.html b/tests/functional/web/alert.html index 079d75130..4bf78680a 100644 --- a/tests/functional/web/alert.html +++ b/tests/functional/web/alert.html @@ -7,13 +7,18 @@

    - Open alert + Open alert
    - Open confirm + + Open alert after 1 second +
    - Open prompt + Open confirm +
    + + Open prompt

    From 0bb2c95d673d0a6ee10e92381ac9a0bfd304c6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Sat, 9 May 2020 12:10:48 +0200 Subject: [PATCH 050/276] Fix RemoteWebDriver cannot be instantiated without second parameter (fixes #789) --- lib/Chrome/ChromeDriver.php | 2 +- lib/Remote/RemoteWebDriver.php | 9 ++++----- tests/functional/RemoteWebDriverCreateTest.php | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index 1c9828c8e..a9ead161b 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -35,7 +35,7 @@ public function startSession(DesiredCapabilities $desired_capabilities) null, DriverCommand::NEW_SESSION, [ - 'desiredCapabilities' => $desired_capabilities->toArray(), + 'desiredCapabilities' => (object) $desired_capabilities->toArray(), ] ); $response = $this->executor->execute($command); diff --git a/lib/Remote/RemoteWebDriver.php b/lib/Remote/RemoteWebDriver.php index b5f53246f..f1a47fe44 100644 --- a/lib/Remote/RemoteWebDriver.php +++ b/lib/Remote/RemoteWebDriver.php @@ -93,7 +93,6 @@ public static function create( $http_proxy_port = null, DesiredCapabilities $required_capabilities = null ) { - // BC layer to not break the method signature $selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url); $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities); @@ -109,12 +108,12 @@ public static function create( // W3C $parameters = [ 'capabilities' => [ - 'firstMatch' => [$desired_capabilities->toW3cCompatibleArray()], + 'firstMatch' => [(object) $desired_capabilities->toW3cCompatibleArray()], ], ]; if ($required_capabilities !== null && !empty($required_capabilities->toArray())) { - $parameters['capabilities']['alwaysMatch'] = $required_capabilities->toW3cCompatibleArray(); + $parameters['capabilities']['alwaysMatch'] = (object) $required_capabilities->toW3cCompatibleArray(); } // Legacy protocol @@ -122,10 +121,10 @@ public static function create( // TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities. // This has changed with the W3C WebDriver spec, but is the only way how to pass these // values with the legacy protocol. - $desired_capabilities->setCapability('requiredCapabilities', $required_capabilities->toArray()); + $desired_capabilities->setCapability('requiredCapabilities', (object) $required_capabilities->toArray()); } - $parameters['desiredCapabilities'] = $desired_capabilities->toArray(); + $parameters['desiredCapabilities'] = (object) $desired_capabilities->toArray(); $command = new WebDriverCommand( null, diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index 4eb7ee507..db379964d 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -78,6 +78,22 @@ public function testShouldCreateWebDriverWithRequiredCapabilities() $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); } + /** + * Capabilities (browser name) must be defined when executing via Selenium proxy (standalone server, Saucelabs etc.) + * @group exclude-saucelabs + */ + public function testShouldCreateWebDriverWithoutCapabilities() + { + if (getenv('GECKODRIVER') !== '1' && getenv('CHROMEDRIVER') !== '1') { + $this->markTestSkipped('This test makes sense only when run directly via specific browser driver'); + } + + $this->driver = RemoteWebDriver::create($this->serverUrl); + + $this->assertInstanceOf(RemoteWebDriver::class, $this->driver); + $this->assertNotEmpty($this->driver->getSessionID()); + } + public function testShouldCreateInstanceFromExistingSessionId() { // Create driver instance and load page "index.html" From 53b023cd48af86c30e8cf182146a402b4f09c260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 12 May 2020 23:59:42 +0200 Subject: [PATCH 051/276] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ff306a8..33c219c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Fixed +- Make `alertIsPresent()` condition working in W3C mode. +- `RemoteWebDriver::create()` cannot be used without providing the second parameter (which is in fact optional). ## 1.8.2 - 2020-03-04 ### Changed From 501987c3b8c012a08384c0c65dcffd319d0cebae Mon Sep 17 00:00:00 2001 From: Arnout Boks Date: Tue, 2 Jun 2020 21:33:06 +0200 Subject: [PATCH 052/276] Fix ChromeDriver::start() causes 'mixed' W3c mode The `new static` within ChromeDriver::start() creates a RemoteWebDriver that is not W3C compatible by default (due to the default for RemoteWebDriver's 3rd constructor arg). The command executor it uses assumes W3C compatibility by default though. This causes strange bugs, where commands are created assuming non-compliance, but translated by the command executor as if they were W3C compliant. By using the logic already present in RemoteWebDriver::create(), ChromeDriver now detects whether the sesson it started is in W3C compatible mode and updates the flags both on itself and on its executor. --- lib/Chrome/ChromeDriver.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Chrome/ChromeDriver.php b/lib/Chrome/ChromeDriver.php index a9ead161b..1b77169fb 100644 --- a/lib/Chrome/ChromeDriver.php +++ b/lib/Chrome/ChromeDriver.php @@ -39,6 +39,12 @@ public function startSession(DesiredCapabilities $desired_capabilities) ] ); $response = $this->executor->execute($command); + $value = $response->getValue(); + + if (!$this->isW3cCompliant = isset($value['capabilities'])) { + $this->executor->disableW3cCompliance(); + } + $this->sessionID = $response->getSessionID(); } From e4347e2164d56c9ad20911f37d41919a0eaadf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 18 Jun 2020 19:43:24 +0200 Subject: [PATCH 053/276] Rename default branch to main --- .github/CONTRIBUTING.md | 2 +- README.md | 2 +- composer.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2fdbb677f..ed13ceed8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,7 +14,7 @@ The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) 2. Implement your code changes into separate branch 3. Make sure all PHPUnit tests passes and code-style matches PSR-2 (see below). We also have Travis CI build which will automatically run tests on your pull request. 4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md) -5. Submit your [pull request](https://github.com/php-webdriver/php-webdriver/pulls) against `master` branch +5. Submit your [pull request](https://github.com/php-webdriver/php-webdriver/pulls) against `main` branch When you are going to contribute, please keep in mind that this webdriver client aims to be as close as possible to other languages Java/Ruby/Python/C#. FYI, here is the overview of [the official Java API](http://seleniumhq.github.io/selenium/docs/api/java/) diff --git a/README.md b/README.md index 6585cd227..c69dea366 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # php-webdriver – Selenium WebDriver bindings for PHP [![Latest Stable Version](https://img.shields.io/packagist/v/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) -[![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/master.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) +[![Travis Build](https://img.shields.io/travis/php-webdriver/php-webdriver/main.svg?style=flat-square)](https://travis-ci.com/php-webdriver/php-webdriver) [![Sauce Test Status](https://saucelabs.com/buildstatus/php-webdriver)](https://saucelabs.com/u/php-webdriver) [![Total Downloads](https://img.shields.io/packagist/dd/php-webdriver/webdriver.svg?style=flat-square)](https://packagist.org/packages/php-webdriver/webdriver) diff --git a/composer.json b/composer.json index 32014e38c..7c0f1fdc3 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-main": "1.8.x-dev" } }, "autoload": { From 6916b0bf61ab19b9d06f50f3c79b209e17f4c9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 4 Aug 2020 13:53:57 +0200 Subject: [PATCH 054/276] Minor improvements and typos fixes --- lib/Remote/RemoteWebElement.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index f8ee1d1fd..0ca59aba7 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -81,8 +81,7 @@ public function click() * Find the first WebDriverElement within this element using the given mechanism. * * @param WebDriverBy $by - * @return RemoteWebElement NoSuchElementException is thrown in - * HttpCommandExecutor if no element is found. + * @return RemoteWebElement NoSuchElementException is thrown in HttpCommandExecutor if no element is found. * @see WebDriverBy */ public function findElement(WebDriverBy $by) @@ -213,10 +212,10 @@ public function getCoordinates() $element = $this; $on_screen = null; // planned but not yet implemented - $in_view_port = function () use ($element) { + $in_view_port = static function () use ($element) { return $element->getLocationOnScreenOnceScrolledIntoView(); }; - $on_page = function () use ($element) { + $on_page = static function () use ($element) { return $element->getLocation(); }; $auxiliary = $this->getID(); @@ -304,7 +303,7 @@ public function isEnabled() } /** - * Determine whether or not this element is selected or not. + * Determine whether this element is selected or not. * * @return bool */ @@ -367,8 +366,7 @@ public function sendKeys($value) } /** - * Set the fileDetector in order to let the RemoteWebElement to know that - * you are going to upload a file. + * Set the fileDetector in order to let the RemoteWebElement to know that you are going to upload a file. * * Basically, if you want WebDriver trying to send a file, set the fileDetector * to be LocalFileDetector. Otherwise, keep it UselessFileDetector. @@ -427,7 +425,7 @@ public function getID() } /** - * Take screenshot of a specific element. + * Take a screenshot of a specific element. * * @param string $save_as The path of the screenshot to be saved. * @return string The screenshot in PNG format. @@ -454,7 +452,7 @@ public function takeElementScreenshot($save_as = null) } /** - * Test if two element IDs refer to the same DOM element. + * Test if two elements IDs refer to the same DOM element. * * @param WebDriverElement $other * @return bool From e2ae45a78370e2000711ba60de16d7f13317a53a Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Fri, 26 Jun 2020 11:02:41 +0800 Subject: [PATCH 055/276] Work around NULL key issue in sendKeys A long-standing geckodriver bug (https://bugzilla.mozilla.org/show_bug.cgi?id=1494661) means that it is not possible to send a key combination such as SHIFT + 'h' + NULL + 'ello'. In this case the NULL key does not clear the SHIFT modifier as per the specification, and it additionally prints a character for the NULL key. It is possible to work around this bug by splitting on the encoded key and sending the input in multiple commands instead. Geckodriver already sends an implicity NULL at the end of the sendKeys command which does work, does release the modifier and does not print any character. --- lib/Remote/RemoteWebElement.php | 24 +++++++++++++++-------- tests/functional/RemoteWebElementTest.php | 8 ++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/Remote/RemoteWebElement.php b/lib/Remote/RemoteWebElement.php index 0ca59aba7..b4b640374 100644 --- a/lib/Remote/RemoteWebElement.php +++ b/lib/Remote/RemoteWebElement.php @@ -325,14 +325,20 @@ public function sendKeys($value) { $local_file = $this->fileDetector->getLocalFile($value); + $params = []; if ($local_file === null) { if ($this->isW3cCompliant) { - $params = [ - 'text' => WebDriverKeys::encode($value, true), - ':id' => $this->id, - ]; + // Work around the Geckodriver NULL issue by splitting on NULL and calling sendKeys multiple times. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1494661. + $encodedValues = explode(WebDriverKeys::NULL, WebDriverKeys::encode($value, true)); + foreach ($encodedValues as $encodedValue) { + $params[] = [ + 'text' => $encodedValue, + ':id' => $this->id, + ]; + } } else { - $params = [ + $params[] = [ 'value' => WebDriverKeys::encode($value), ':id' => $this->id, ]; @@ -348,19 +354,21 @@ public function sendKeys($value) $fileName = $local_file; } - $params = [ + $params[] = [ 'text' => $fileName, ':id' => $this->id, ]; } else { - $params = [ + $params[] = [ 'value' => WebDriverKeys::encode($this->upload($local_file)), ':id' => $this->id, ]; } } - $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params); + foreach ($params as $param) { + $this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $param); + } return $this; } diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index cacf16390..021e6ed1a 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -152,12 +152,20 @@ public function testShouldSendKeysToFormElement() $input->sendKeys(' baz'); $this->assertSame('foo bar baz', $input->getAttribute('value')); + $input->clear(); + $input->sendKeys([WebDriverKeys::SHIFT, 'H', WebDriverKeys::NULL, 'ello']); + $this->assertSame('Hello', $input->getAttribute('value')); + $textarea->clear(); $textarea->sendKeys('foo bar'); $this->assertSame('foo bar', $textarea->getAttribute('value')); $textarea->sendKeys(' baz'); $this->assertSame('foo bar baz', $textarea->getAttribute('value')); + $textarea->clear(); + $textarea->sendKeys([WebDriverKeys::SHIFT, 'H', WebDriverKeys::NULL, 'ello']); + $this->assertSame('Hello', $textarea->getAttribute('value')); + // Send keys as array $textarea->clear(); $textarea->sendKeys(['bat', 1, '3', ' ', 3, '7']); From 99ec34e9ee006a80042dd860f17010f13ddabed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Wed, 9 Sep 2020 17:44:26 +0200 Subject: [PATCH 056/276] Update travis build to latest geckodriver --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a773b2c6f..134f39466 100644 --- a/.travis.yml +++ b/.travis.yml @@ -132,7 +132,7 @@ before_script: unzip chromedriver_linux64.zip -d chromedriver; fi - if [ "$BROWSER_NAME" = "chrome" ]; then export CHROMEDRIVER_PATH=$PWD/chromedriver/chromedriver; fi - - if [ "$GECKODRIVER" = "1" ]; then mkdir -p geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz; tar xzf geckodriver-v0.26.0-linux64.tar.gz -C geckodriver; fi + - if [ "$GECKODRIVER" = "1" ]; then mkdir -p geckodriver; wget -q -t 3 https://github.com/mozilla/geckodriver/releases/download/v0.27.0/geckodriver-v0.27.0-linux64.tar.gz; tar xzf geckodriver-v0.27.0-linux64.tar.gz -C geckodriver; fi - if [ ! -f jar/selenium-server-standalone.jar ] && [ -n "$SELENIUM_SERVER" ]; then mkdir -p jar; if [ "$SELENIUM_SERVER" = "legacy" ]; then From d01e823a2605118f41638e7d8ebcce870ff70e1d Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Mon, 22 Jun 2020 23:55:53 +0300 Subject: [PATCH 057/276] Make sure that chromeOptions is an object when empty --- lib/Chrome/ChromeOptions.php | 14 ++++++---- lib/Remote/DesiredCapabilities.php | 8 ++++-- tests/unit/Remote/DesiredCapabilitiesTest.php | 28 +++++++++++++------ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/lib/Chrome/ChromeOptions.php b/lib/Chrome/ChromeOptions.php index af99d3cfe..1b3c4cbdc 100644 --- a/lib/Chrome/ChromeOptions.php +++ b/lib/Chrome/ChromeOptions.php @@ -117,17 +117,19 @@ public function toCapabilities() } /** - * @return array + * @return \ArrayObject|array */ public function toArray() { - $options = $this->experimentalOptions; - // The selenium server expects a 'dictionary' instead of a 'list' when // reading the chrome option. However, an empty array in PHP will be - // converted to a 'list' instead of a 'dictionary'. To fix it, we always - // set the 'binary' to avoid returning an empty array. - $options['binary'] = $this->binary; + // converted to a 'list' instead of a 'dictionary'. To fix it, we work + // with `ArrayObject` + $options = new \ArrayObject($this->experimentalOptions); + + if (!empty($this->binary)) { + $options['binary'] = $this->binary; + } if (!empty($this->arguments)) { $options['args'] = $this->arguments; diff --git a/lib/Remote/DesiredCapabilities.php b/lib/Remote/DesiredCapabilities.php index e022ccecd..5fcf651d9 100644 --- a/lib/Remote/DesiredCapabilities.php +++ b/lib/Remote/DesiredCapabilities.php @@ -235,9 +235,11 @@ public function toW3cCompatibleArray() // Convert ChromeOptions if (array_key_exists(ChromeOptions::CAPABILITY, $ossCapabilities)) { if (array_key_exists(ChromeOptions::CAPABILITY_W3C, $ossCapabilities)) { - $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = array_merge_recursive( - $ossCapabilities[ChromeOptions::CAPABILITY], - $ossCapabilities[ChromeOptions::CAPABILITY_W3C] + $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = new \ArrayObject( + array_merge_recursive( + (array) $ossCapabilities[ChromeOptions::CAPABILITY], + (array) $ossCapabilities[ChromeOptions::CAPABILITY_W3C] + ) ); } else { $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = $ossCapabilities[ChromeOptions::CAPABILITY]; diff --git a/tests/unit/Remote/DesiredCapabilitiesTest.php b/tests/unit/Remote/DesiredCapabilitiesTest.php index f74eb754d..f24d8eb40 100644 --- a/tests/unit/Remote/DesiredCapabilitiesTest.php +++ b/tests/unit/Remote/DesiredCapabilitiesTest.php @@ -213,15 +213,24 @@ public function provideW3cCapabilities() 'vendor:prefix' => 'vendor extension should be kept', ], ], + 'chromeOptions should be an object if empty' => [ + new DesiredCapabilities([ + ChromeOptions::CAPABILITY => new ChromeOptions(), + ]), + [ + 'goog:chromeOptions' => new \ArrayObject(), + ], + ], 'chromeOptions should be converted' => [ new DesiredCapabilities([ ChromeOptions::CAPABILITY => $chromeOptions, ]), [ - 'goog:chromeOptions' => [ - 'args' => ['--headless'], - 'binary' => '', - ], + 'goog:chromeOptions' => new \ArrayObject( + [ + 'args' => ['--headless'], + ] + ), ], ], 'chromeOptions should be merged if already defined' => [ @@ -233,11 +242,12 @@ public function provideW3cCapabilities() ], ]), [ - 'goog:chromeOptions' => [ - 'args' => ['--headless', 'window-size=1024,768'], - 'binary' => '', - 'debuggerAddress' => '127.0.0.1:38947', - ], + 'goog:chromeOptions' => new \ArrayObject( + [ + 'args' => ['--headless', 'window-size=1024,768'], + 'debuggerAddress' => '127.0.0.1:38947', + ] + ), ], ], 'firefox_profile should be converted' => [ From 33284ca385542df62a15ee53cc82eef33ca0c407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Thu, 10 Sep 2020 13:45:09 +0200 Subject: [PATCH 058/276] Run SauceLabs tests via GitHub Actions --- .github/workflows/sauce-labs.yaml | 66 ++++++++++++++++++++++++++ .travis.yml | 46 +----------------- composer.json | 1 + tests/functional/WebDriverTestCase.php | 26 +++++++--- 4 files changed, 88 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/sauce-labs.yaml diff --git a/.github/workflows/sauce-labs.yaml b/.github/workflows/sauce-labs.yaml new file mode 100644 index 000000000..9398909ae --- /dev/null +++ b/.github/workflows/sauce-labs.yaml @@ -0,0 +1,66 @@ +name: Sauce Labs + +on: + push: + schedule: + - cron: '0 3 * * *' + +jobs: + tests: + runs-on: ubuntu-latest + env: + SAUCELABS: 1 + SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} + SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} + strategy: + fail-fast: false + matrix: + include: + - { name: "Firefox 47, OSS protocol", BROWSER_NAME: "firefox", VERSION: "47.0", PLATFORM: "Windows 10", DISABLE_W3C_PROTOCOL: "1", tunnel-id: "gh-1" } + - { name: "Chrome 74, OSS protocol", BROWSER_NAME: "chrome", VERSION: "74.0", PLATFORM: "Windows 10", DISABLE_W3C_PROTOCOL: "1", tunnel-id: "gh-2" } # 74 is the last version which don't use W3C WebDriver by default + - { name: "Chrome latest, W3C protocol", BROWSER_NAME: "chrome", VERSION: "latest", PLATFORM: "Windows 10", tunnel-id: "gh-3" } + - { name: "Edge latest, W3C protocol", BROWSER_NAME: "MicrosoftEdge", VERSION: "latest", PLATFORM: "Windows 10", tunnel-id: "gh-4" } + + name: ${{ matrix.name }} (${{ matrix.tunnel-id }}) + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: mbstring, intl, zip + + - name: Install dependencies + run: composer update --no-interaction + + - name: Start local PHP server + run: | + php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & + + - name: Start Sauce Connect + uses: saucelabs/sauce-connect-action@master + with: + username: ${{ secrets.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + tunnelIdentifier: ${{ matrix.tunnel-id }} + + - name: Run tests + env: + BROWSER_NAME: ${{ matrix.BROWSER_NAME }} + VERSION: ${{ matrix.VERSION }} + PLATFORM: ${{ matrix.PLATFORM }} + DISABLE_W3C_PROTOCOL: ${{ matrix.DISABLE_W3C_PROTOCOL }} + SAUCE_TUNNEL_IDENTIFIER: ${{ matrix.tunnel-id }} + run: | + if [ -n "$SAUCELABS" ]; then EXCLUDE_GROUP+="exclude-saucelabs,"; fi + if [ "$BROWSER_NAME" = "MicrosoftEdge" ]; then EXCLUDE_GROUP+="exclude-edge,"; fi + if [ "$BROWSER_NAME" = "firefox" ]; then EXCLUDE_GROUP+="exclude-firefox,"; fi + if [ "$BROWSER_NAME" = "chrome" ]; then EXCLUDE_GROUP+="exclude-chrome,"; fi + if [ -n "$EXCLUDE_GROUP" ]; then EXTRA_PARAMS+=" --exclude-group $EXCLUDE_GROUP"; fi + ./vendor/bin/phpunit --coverage-clover ./logs/coverage-clover.xml $EXTRA_PARAMS + + - name: Print logs + if: ${{ always() }} + run: | + if [ -f ./logs/php-server.log ]; then cat ./logs/php-server.log; fi diff --git a/.travis.yml b/.travis.yml index 134f39466..a627edc09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,51 +70,6 @@ matrix: addons: chrome: stable - # Saucelabs builds - - name: 'Sauce Labs, Firefox 47, OSS protocol' - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="firefox" VERSION="47.0" PLATFORM="Windows 10" DISABLE_W3C_PROTOCOL="1" - before_script: - - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" - addons: - sauce_connect: true - jwt: - secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - - - name: 'Sauce Labs, Chrome 74, OSS protocol' - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="74.0" PLATFORM="Windows 10" DISABLE_W3C_PROTOCOL="1" # 74 is the last version which don't use W3C WebDriver by default - before_script: - - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" - addons: - sauce_connect: true - jwt: - secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - - - name: 'Sauce Labs, Chrome latest, W3C protocol' - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="chrome" VERSION="latest" PLATFORM="Windows 10" - before_script: - - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" - addons: - sauce_connect: true - jwt: - secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - - - name: 'Sauce Labs, Edge latest, W3C protocol' - php: '7.3' - env: SAUCELABS=1 BROWSER_NAME="MicrosoftEdge" VERSION="latest" PLATFORM="Windows 10" - before_script: - - php -S 127.0.0.1:8000 -t tests/functional/web/ &>>./logs/php-server.log & - - until $(echo | nc localhost 8000); do sleep 1; echo waiting for PHP server on port 8000...; done; echo "PHP server started" - addons: - sauce_connect: true - jwt: - secure: 5s8iQfH1dHgEm0DeP9VZ/MCzCeiE/HnMWqPFzRmg6VD2qJ53oYdseo8j+QCbE25MIwoSnIbKzlnbCN6fVzZc/0S7Mo45xJiq8xVLPSdMjDoOeqYE4of+t5Srq4iSzGLPCLiMTtB4xDEl6blUVGhYxN5rA/tVN+cVtLNQvo3ovRon3Mw3MqR4pgCE6PofcLXtyJc3KuOBlUJLWdPGRdlZrpKWE5ogyj4a1h4bVwidckZqkOF+gm58Gf0zVfFazDQFIw2Xuq7SZmiNgdOD5yUEePkrMhy2tbOlPNAIgHCpzHldv5Y+GYyxIYHZ0mGlGxHrfjrcAoSA6r2iXB9q2ijLVwqOARpcvGcBzZBil9aMAHRIXHAOV9Ihv4velrzmiLKADtD60Bfj2zzntGYZA3EGucitMMkkP7vfAa769i5QWK1Lniq3+VUuGNVjRzl4GuQPpc0wMWeJvQGc5Uf9Kk/sOCkPp0SPWcZ6nNAUebRy3V5OoADA9IntyXxfTlZdOHSbJTsG+eOGve0uLGRAOS+oeCstO7Gk4e/Ylozju+ixkINEY7HHDGt6AyHGtjPdy08Y0XrIqs0JMxsHKrtTVNxDjIFKbMees+vtxU3DEr/tNo1sTo34ieGKZP2Cp5mG/IrcjD1saebUaCngQO3QfeuKcU8pBTR7l7PtFNHm3HrmdkY= - cache: directories: - $HOME/.composer/cache @@ -156,6 +111,7 @@ before_script: script: - if [ -n "$SAUCELABS" ]; then EXCLUDE_GROUP+="exclude-saucelabs,"; fi + - if [ -n "$SAUCELABS" ]; then export SAUCE_TUNNEL_IDENTIFIER="$TRAVIS_JOB_NUMBER"; fi - if [ "$BROWSER_NAME" = "MicrosoftEdge" ]; then EXCLUDE_GROUP+="exclude-edge,"; fi - if [ "$BROWSER_NAME" = "firefox" ]; then EXCLUDE_GROUP+="exclude-firefox,"; fi - if [ "$BROWSER_NAME" = "chrome" ]; then EXCLUDE_GROUP+="exclude-chrome,"; fi diff --git a/composer.json b/composer.json index 7c0f1fdc3..b94e7ac94 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", + "ondram/ci-detector": "^2.1 || ^3.5", "php-coveralls/php-coveralls": "^2.0", "php-mock/php-mock-phpunit": "^1.1", "php-parallel-lint/php-parallel-lint": "^1.2", diff --git a/tests/functional/WebDriverTestCase.php b/tests/functional/WebDriverTestCase.php index 9718cd671..76c79bb7d 100644 --- a/tests/functional/WebDriverTestCase.php +++ b/tests/functional/WebDriverTestCase.php @@ -8,6 +8,7 @@ use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\WebDriverBrowserType; +use OndraM\CiDetector\CiDetector; use PHPUnit\Framework\TestCase; /** @@ -174,9 +175,18 @@ protected function setUpSauceLabs() $name = get_class($this) . '::' . $this->getName(); $tags = [get_class($this)]; - if (getenv('TRAVIS_JOB_NUMBER')) { - $tunnelIdentifier = getenv('TRAVIS_JOB_NUMBER'); - $build = getenv('TRAVIS_JOB_NUMBER'); + $ciDetector = new CiDetector(); + if ($ciDetector->isCiDetected()) { + $ci = $ciDetector->detect(); + if (!empty($ci->getBuildNumber())) { + // SAUCE_TUNNEL_IDENTIFIER appended as a workaround for GH actions not having environment value + // to distinguish runs of the matrix + $build = $ci->getBuildNumber() . '.' . getenv('SAUCE_TUNNEL_IDENTIFIER'); + } + } + + if (getenv('SAUCE_TUNNEL_IDENTIFIER')) { + $tunnelIdentifier = getenv('SAUCE_TUNNEL_IDENTIFIER'); } if (!getenv('DISABLE_W3C_PROTOCOL')) { @@ -184,17 +194,21 @@ protected function setUpSauceLabs() 'name' => $name, 'tags' => $tags, ]; - if (isset($tunnelIdentifier, $build)) { - $sauceOptions['tunnelIdentifier'] = $tunnelIdentifier; + if (isset($build)) { $sauceOptions['build'] = $build; } + if (isset($tunnelIdentifier)) { + $sauceOptions['tunnelIdentifier'] = $tunnelIdentifier; + } $this->desiredCapabilities->setCapability('sauce:options', (object) $sauceOptions); } else { $this->desiredCapabilities->setCapability('name', $name); $this->desiredCapabilities->setCapability('tags', $tags); - if (isset($tunnelIdentifier, $build)) { + if (isset($tunnelIdentifier)) { $this->desiredCapabilities->setCapability('tunnel-identifier', $tunnelIdentifier); + } + if (isset($build)) { $this->desiredCapabilities->setCapability('build', $build); } } From 0ac00d8deca08b2c5a94dd9f25533588da94c8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 6 Oct 2020 20:22:34 +0200 Subject: [PATCH 059/276] Disable composer memory limit in travis builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a627edc09..31c92bd5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ env: - DISPLAY=:99.0 - BROWSER_NAME="htmlunit" - SELENIUM_SERVER="https://selenium-release.storage.googleapis.com/3.14/selenium-server-standalone-3.14.0.jar" # Latest version including HtmlUnit + - COMPOSER_MEMORY_LIMIT=-1 services: - xvfb From d5790a8daea2172dc3923b1565aed8df12922177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 6 Oct 2020 21:09:25 +0200 Subject: [PATCH 060/276] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c219c31..b4ceccbda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Make `alertIsPresent()` condition working in W3C mode. - `RemoteWebDriver::create()` cannot be used without providing the second parameter (which is in fact optional). +- `ChromeDriver::start()` starts in inconsistent state mixing W3C/OSS mode. +- Modifier keys are not released when sending NULL key in GeckoDriver (workaround for GeckoDriver bug [1494661](https://bugzilla.mozilla.org/show_bug.cgi?id=1494661)). +- Do not set unnecessary `binary` value of `goog:chromeOptions` while keep the object in proper data type required by ChromeDriver. ## 1.8.2 - 2020-03-04 ### Changed From fb0fc4cb01c70a7790a5fcc91d461b88c83174a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 6 Oct 2020 21:10:04 +0200 Subject: [PATCH 061/276] Release version 1.8.3 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ceccbda..c4f091d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## 1.8.3 - 2020-10-06 ### Fixed - Make `alertIsPresent()` condition working in W3C mode. - `RemoteWebDriver::create()` cannot be used without providing the second parameter (which is in fact optional). From 841b5b7e099aed453b67b617014f79b822688f90 Mon Sep 17 00:00:00 2001 From: Michael Steininger <11192306+codegain@users.noreply.github.com> Date: Fri, 18 Sep 2020 22:38:24 +0200 Subject: [PATCH 062/276] Add same-site support for cookies (fixes #705) --- lib/Cookie.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/Cookie.php b/lib/Cookie.php index 0e1436089..1005bd0dc 100644 --- a/lib/Cookie.php +++ b/lib/Cookie.php @@ -58,6 +58,9 @@ public static function createFromArray(array $cookieArray) if (isset($cookieArray['httpOnly'])) { $cookie->setHttpOnly($cookieArray['httpOnly']); } + if (isset($cookieArray['sameSite'])) { + $cookie->setSameSite($cookieArray['sameSite']); + } return $cookie; } @@ -172,6 +175,24 @@ public function isHttpOnly() return $this->offsetGet('httpOnly'); } + /** + * The cookie's same-site value. + * + * @param string $sameSite + */ + public function setSameSite($sameSite) + { + $this->offsetSet('sameSite', $sameSite); + } + + /** + * @return string|null + */ + public function getSameSite() + { + return $this->offsetGet('sameSite'); + } + /** * @return array */ From 7efbcb88a34b1df5aeaa1c40bf20d96388633d09 Mon Sep 17 00:00:00 2001 From: Michael Steininger <11192306+codegain@users.noreply.github.com> Date: Tue, 6 Oct 2020 22:07:06 +0200 Subject: [PATCH 063/276] added unit tests for same-site cookie attribute --- tests/unit/CookieTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index 621fb65c0..cced57524 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -17,6 +17,7 @@ public function testShouldSetAllProperties() $cookie->setExpiry(1485388387); $cookie->setSecure(true); $cookie->setHttpOnly(true); + $cookie->setSameSite('Lax'); $this->assertSame('cookieName', $cookie->getName()); $this->assertSame('someValue', $cookie->getValue()); @@ -25,6 +26,7 @@ public function testShouldSetAllProperties() $this->assertSame(1485388387, $cookie->getExpiry()); $this->assertTrue($cookie->isSecure()); $this->assertTrue($cookie->isHttpOnly()); + $this->assertSame('Lax', $cookie->getSameSite()); return $cookie; } @@ -44,6 +46,7 @@ public function testShouldBeConvertibleToArray(Cookie $cookie) 'expiry' => 1485388387, 'secure' => true, 'httpOnly' => true, + 'sameSite' => 'Lax', ], $cookie->toArray() ); @@ -84,6 +87,7 @@ public function testShouldProvideArrayAccessToProperties(Cookie $cookie) $this->assertSame(1485388387, $cookie['expiry']); $this->assertTrue($cookie['secure']); $this->assertTrue($cookie['httpOnly']); + $this->assertSame('Lax', $cookie['sameSite']); $cookie->offsetSet('domain', 'bar.com'); $this->assertSame('bar.com', $cookie['domain']); @@ -122,6 +126,10 @@ public function testShouldBeCreatableFromAnArrayWithBasicValues() $this->assertArrayNotHasKey('httpOnly', $cookie); $this->assertNull($cookie['httpOnly']); $this->assertNull($cookie->isHttpOnly()); + + $this->assertArrayNotHasKey('sameSite', $cookie); + $this->assertNull($cookie['sameSite']); + $this->assertNull($cookie->getSameSite()); } public function testShouldBeCreatableFromAnArrayWithAllValues() @@ -134,6 +142,7 @@ public function testShouldBeCreatableFromAnArrayWithAllValues() 'expiry' => 1485388333, 'secure' => false, 'httpOnly' => false, + 'sameSite' => 'Lax', ]; $cookie = Cookie::createFromArray($sourceArray); @@ -145,6 +154,7 @@ public function testShouldBeCreatableFromAnArrayWithAllValues() $this->assertSame(1485388333, $cookie['expiry']); $this->assertFalse($cookie['secure']); $this->assertFalse($cookie['httpOnly']); + $this->assertSame('Lax', $cookie['sameSite']); } /** From 4fbb161f0a480b48cce0116af581c61c3fd8c347 Mon Sep 17 00:00:00 2001 From: Michael Steininger <11192306+codegain@users.noreply.github.com> Date: Tue, 6 Oct 2020 22:38:12 +0200 Subject: [PATCH 064/276] Updated testShouldNotContainNullValues --- tests/unit/CookieTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/CookieTest.php b/tests/unit/CookieTest.php index cced57524..d58419a9a 100644 --- a/tests/unit/CookieTest.php +++ b/tests/unit/CookieTest.php @@ -67,6 +67,7 @@ public function testShouldNotContainNullValues() $cookie->setHttpOnly(null); $cookie->setPath(null); + $cookie->setSameSite(null); $cookieArray = $cookie->toArray(); foreach ($cookieArray as $key => $value) { From c106a41a1a75e3e3e163f6a3f58aeec80e434b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Tue, 6 Oct 2020 23:12:46 +0200 Subject: [PATCH 065/276] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4f091d8a..5009ff1dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ This project versioning adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added +- Support of SameSite cookie property. ## 1.8.3 - 2020-10-06 ### Fixed From 9e8aeac43ec9e3e2f530c7662ecb67cbb4150495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 16 Nov 2020 15:26:32 +0100 Subject: [PATCH 066/276] Move phpstan path and level config to file --- phpstan.neon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpstan.neon b/phpstan.neon index b0777e2c2..846484976 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,9 @@ parameters: + level: 2 + paths: + - lib/ + - tests/ + ignoreErrors: # To be fixed: - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#' From 5898a74ce2bb87b2b755d322069200c7460fe907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Machulda?= Date: Mon, 16 Nov 2020 15:30:31 +0100 Subject: [PATCH 067/276] Workaround for broken PHPStan parallel processing --- composer.json | 3 ++- phpstan-webdriverkeys.neon | 6 ++++++ phpstan.neon | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 phpstan-webdriverkeys.neon diff --git a/composer.json b/composer.json index b94e7ac94..0a3e81ae3 100644 --- a/composer.json +++ b/composer.json @@ -68,7 +68,8 @@ "scripts": { "analyze": [ "vendor/bin/parallel-lint -j 10 ./lib ./tests example.php", - "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi" + "vendor/bin/phpstan.phar analyze -c phpstan.neon --ansi", + "vendor/bin/phpstan.phar analyze -c phpstan-webdriverkeys.neon --ansi" ], "codestyle:check": [ "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff --dry-run -vvv --ansi", diff --git a/phpstan-webdriverkeys.neon b/phpstan-webdriverkeys.neon new file mode 100644 index 000000000..799558876 --- /dev/null +++ b/phpstan-webdriverkeys.neon @@ -0,0 +1,6 @@ +# WebDriverKeys.php breaks PHPStan parallel processing, so we must analyze the file separately. +# See https://github.com/phpstan/phpstan/issues/3956 and https://github.com/clue/reactphp-ndjson/issues/21 +parameters: + level: 2 + paths: + - lib/WebDriverKeys.php diff --git a/phpstan.neon b/phpstan.neon index 846484976..4b12710a5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -16,3 +16,6 @@ parameters: path: 'lib/Remote/RemoteWebDriver.php' inferPrivatePropertyTypeFromConstructor: true + + excludes_analyse: + - lib/WebDriverKeys.php From 4d2eb507e6308b8794ddf0b2e75be245bbff967c Mon Sep 17 00:00:00 2001 From: William Desportes Date: Mon, 16 Nov 2020 16:22:05 +0100 Subject: [PATCH 068/276] Scripts and configuration changes for PHP 8 Co-Authored-By: Dries Vints --- .gitattributes | 1 + .github/workflows/php.yaml | 2 +- .gitignore | 1 + .php_cs.dist | 2 +- .travis.yml | 22 ++++++++++++++++++---- composer.json | 10 ++++------ scripts/apply-phpunit-patches.sh | 20 ++++++++++++++++++++ 7 files changed, 46 insertions(+), 12 deletions(-) create mode 100755 scripts/apply-phpunit-patches.sh diff --git a/.gitattributes b/.gitattributes index 3123b82f2..8a5e272b2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ * text=auto +/scripts export-ignore /tests export-ignore /.gitattributes export-ignore /.gitignore export-ignore diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml index c96bec74e..3065ff732 100644 --- a/.github/workflows/php.yaml +++ b/.github/workflows/php.yaml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: Setup PHP - uses: shivammathur/setup-php@v1 + uses: shivammathur/setup-php@v2 with: php-version: '7.4' extensions: mbstring, intl, zip diff --git a/.gitignore b/.gitignore index deb25f3ae..d5605367c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ composer.phar composer.lock vendor .php_cs.cache +.phpunit.result.cache phpunit.xml logs/ diff --git a/.php_cs.dist b/.php_cs.dist index b771f8b04..a438f2095 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -52,7 +52,7 @@ return PhpCsFixer\Config::create() 'ordered_class_elements' => true, 'ordered_imports' => true, 'php_unit_construct' => true, - 'php_unit_dedicate_assert' => true, + 'php_unit_dedicate_assert' => false, 'php_unit_expectation' => ['target' => '5.6'], 'php_unit_method_casing' => ['case' => 'camel_case'], 'php_unit_mock' => true, diff --git a/.travis.yml b/.travis.yml index 31c92bd5d..b8f993e44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: php dist: xenial php: - - '5.6' - - '7.0' - '7.1' - '7.2' - '7.3' @@ -21,10 +19,25 @@ services: matrix: include: + - name: 'PHP nightly build' + php: 'nightly' + env: DEPENDENCIES="--ignore-platform-req=php" + + - name: 'PHP 7.0' + php: '7.0' + env: RUN_PHPUNIT_PATCHES="true" + + - name: 'PHP 5.6' + php: '5.6' + env: RUN_PHPUNIT_PATCHES="true" + # Build with lowest possible dependencies on lowest possible PHP - name: 'Lowest dependencies build' php: '5.6' - env: DEPENDENCIES="--prefer-lowest" + env: + - DEPENDENCIES="--prefer-lowest" + - RUN_PHPUNIT_PATCHES="true" + # Firefox inside Travis environment - name: 'Firefox 45 on Travis (OSS protocol); via legacy Selenium server' @@ -80,6 +93,7 @@ install: - travis_retry composer update --no-interaction $DEPENDENCIES before_script: + - if [ "$RUN_PHPUNIT_PATCHES" = "true" ]; then ./scripts/apply-phpunit-patches.sh; fi - if [ "$BROWSER_NAME" = "chrome" ]; then mkdir chromedriver; CHROME_VERSION=$(google-chrome --product-version); @@ -126,4 +140,4 @@ after_script: - if [ -f ./logs/chromedriver.log ]; then cat ./logs/chromedriver.log; fi after_success: - - travis_retry php vendor/bin/php-coveralls -v + - if [ "$TRAVIS_PHP_VERSION" != "nightly" ]; then travis_retry php vendor/bin/php-coveralls -v; fi diff --git a/composer.json b/composer.json index 0a3e81ae3..88f215101 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "homepage": "https://github.com/php-webdriver/php-webdriver", "license": "MIT", "require": { - "php": "^5.6 || ~7.0", + "php": "^5.6 || ~7.0 || ^8.0", "ext-curl": "*", "ext-json": "*", "ext-zip": "*", @@ -25,12 +25,10 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", "ondram/ci-detector": "^2.1 || ^3.5", - "php-coveralls/php-coveralls": "^2.0", - "php-mock/php-mock-phpunit": "^1.1", + "php-coveralls/php-coveralls": "^2.4", + "php-mock/php-mock-phpunit": "^1.1 || ^2.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpunit/phpunit": "^5.7", - "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", - "sminnee/phpunit-mock-objects": "^3.4", + "phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9", "squizlabs/php_codesniffer": "^3.5", "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0" }, diff --git a/scripts/apply-phpunit-patches.sh b/scripts/apply-phpunit-patches.sh new file mode 100755 index 000000000..ee1dd00f3 --- /dev/null +++ b/scripts/apply-phpunit-patches.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# All commands below must no fail +set -e + +# Be in the root dir +cd "$(dirname $0)/../" + +find tests/ -type f -print0 | xargs -0 sed -i 's/function setUpBeforeClass(): void/function setUpBeforeClass()/g'; +find tests/ -type f -print0 | xargs -0 sed -i 's/function setUp(): void/function setUp()/g'; +find tests/ -type f -print0 | xargs -0 sed -i 's/function tearDown(): void/function tearDown()/g'; + +sed -i 's/endTest(\\PHPUnit\\Framework\\Test \$test, float \$time): void/endTest(\\PHPUnit_Framework_Test \$test, \$time)/g' tests/functional/ReportSauceLabsStatusListener.php; +sed -i 's/: void/ /g' tests/functional/ReportSauceLabsStatusListener.php; +# Drop the listener from the config file +sed -i '//,+2d' phpunit.xml.dist; +sed -i 's/function runBare(): void/function runBare()/g' tests/functional/WebDriverTestCase.php; + +# Return back to original dir +cd - > /dev/null \ No newline at end of file From 6583dd2fddac651d75ead9189cacc9fec0ef504f Mon Sep 17 00:00:00 2001 From: William Desportes Date: Mon, 16 Nov 2020 12:17:56 +0100 Subject: [PATCH 069/276] PHP 8 and phpunit compatibility changes on source files tests/* --- .../Chrome/ChromeDriverServiceTest.php | 2 +- tests/functional/Chrome/ChromeDriverTest.php | 4 +- tests/functional/RemoteTargetLocatorTest.php | 28 +++++----- .../functional/RemoteWebDriverCreateTest.php | 6 +-- .../RemoteWebDriverFindElementTest.php | 4 +- tests/functional/RemoteWebDriverTest.php | 18 +++---- tests/functional/RemoteWebElementTest.php | 6 +-- .../ReportSauceLabsStatusListener.php | 52 ++++++++++++++++--- tests/functional/WebDriverActionsTest.php | 3 +- tests/functional/WebDriverAlertTest.php | 2 +- tests/functional/WebDriverCheckboxesTest.php | 2 +- .../WebDriverOptionsCookiesTest.php | 2 +- tests/functional/WebDriverRadiosTest.php | 2 +- tests/functional/WebDriverSelectTest.php | 2 +- tests/functional/WebDriverTestCase.php | 22 ++++++-- .../WebDriverButtonReleaseActionTest.php | 6 +-- .../Internal/WebDriverClickActionTest.php | 6 +-- .../WebDriverClickAndHoldActionTest.php | 6 +-- .../WebDriverContextClickActionTest.php | 6 +-- .../Internal/WebDriverCoordinatesTest.php | 22 +++----- .../WebDriverDoubleClickActionTest.php | 6 +-- .../Internal/WebDriverKeyDownActionTest.php | 8 +-- .../Internal/WebDriverKeyUpActionTest.php | 8 +-- .../Internal/WebDriverMouseMoveActionTest.php | 6 +-- .../WebDriverMouseToOffsetActionTest.php | 6 +-- .../Internal/WebDriverSendKeysActionTest.php | 8 +-- tests/unit/Remote/HttpCommandExecutorTest.php | 2 +- tests/unit/Remote/RemoteWebDriverTest.php | 2 +- tests/unit/WebDriverExpectedConditionTest.php | 4 +- tests/unit/WebDriverOptionsTest.php | 4 +- 30 files changed, 151 insertions(+), 104 deletions(-) diff --git a/tests/functional/Chrome/ChromeDriverServiceTest.php b/tests/functional/Chrome/ChromeDriverServiceTest.php index a21727781..1f5baa4f9 100644 --- a/tests/functional/Chrome/ChromeDriverServiceTest.php +++ b/tests/functional/Chrome/ChromeDriverServiceTest.php @@ -11,7 +11,7 @@ */ class ChromeDriverServiceTest extends TestCase { - protected function setUp() + protected function setUp(): void { if (!getenv('BROWSER_NAME') === 'chrome' || getenv('SAUCELABS') || !getenv('CHROMEDRIVER_PATH')) { $this->markTestSkipped('ChromeDriverServiceTest is run only when running against local chrome'); diff --git a/tests/functional/Chrome/ChromeDriverTest.php b/tests/functional/Chrome/ChromeDriverTest.php index 26c9de81d..fd7581008 100644 --- a/tests/functional/Chrome/ChromeDriverTest.php +++ b/tests/functional/Chrome/ChromeDriverTest.php @@ -16,14 +16,14 @@ class ChromeDriverTest extends TestCase /** @var ChromeDriver */ protected $driver; - protected function setUp() + protected function setUp(): void { if (!getenv('BROWSER_NAME') === 'chrome' || getenv('SAUCELABS') || !getenv('CHROMEDRIVER_PATH')) { $this->markTestSkipped('ChromeDriverServiceTest is run only when running against local chrome'); } } - protected function tearDown() + protected function tearDown(): void { if ($this->driver instanceof RemoteWebDriver && $this->driver->getCommandExecutor() !== null) { $this->driver->quit(); diff --git a/tests/functional/RemoteTargetLocatorTest.php b/tests/functional/RemoteTargetLocatorTest.php index 8ee5c96bc..9128502b2 100644 --- a/tests/functional/RemoteTargetLocatorTest.php +++ b/tests/functional/RemoteTargetLocatorTest.php @@ -23,7 +23,7 @@ public function testShouldSwitchToWindow() ); // At first the window should not be switched - $this->assertContains('open_new_window.html', $this->driver->getCurrentURL()); + $this->compatAssertStringContainsString('open_new_window.html', $this->driver->getCurrentURL()); $this->assertSame($originalWindowHandle, $this->driver->getWindowHandle()); /** @@ -38,7 +38,7 @@ public function testShouldSwitchToWindow() $this->driver->switchTo()->window($newWindowHandle); // After switchTo() is called, the active window should be changed - $this->assertContains('index.html', $this->driver->getCurrentURL()); + $this->compatAssertStringContainsString('index.html', $this->driver->getCurrentURL()); $this->assertNotSame($originalWindowHandle, $this->driver->getWindowHandle()); } @@ -64,25 +64,25 @@ public function testShouldSwitchToFrameByItsId() $this->driver->get($this->getTestPageUrl('page_with_frame.html')); - $this->assertContains($parentPage, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($parentPage, $this->driver->getPageSource()); $this->driver->switchTo()->frame(0); - $this->assertContains($firstChildFrame, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($firstChildFrame, $this->driver->getPageSource()); $this->driver->switchTo()->frame(null); - $this->assertContains($parentPage, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($parentPage, $this->driver->getPageSource()); $this->driver->switchTo()->frame(1); - $this->assertContains($secondChildFrame, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($secondChildFrame, $this->driver->getPageSource()); $this->driver->switchTo()->frame(null); - $this->assertContains($parentPage, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($parentPage, $this->driver->getPageSource()); $this->driver->switchTo()->frame(0); - $this->assertContains($firstChildFrame, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($firstChildFrame, $this->driver->getPageSource()); $this->driver->switchTo()->defaultContent(); - $this->assertContains($parentPage, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($parentPage, $this->driver->getPageSource()); } public function testShouldSwitchToParentFrame() @@ -92,13 +92,13 @@ public function testShouldSwitchToParentFrame() $this->driver->get($this->getTestPageUrl('page_with_frame.html')); - $this->assertContains($parentPage, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($parentPage, $this->driver->getPageSource()); $this->driver->switchTo()->frame(0); - $this->assertContains($firstChildFrame, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($firstChildFrame, $this->driver->getPageSource()); $this->driver->switchTo()->parent(); - $this->assertContains($parentPage, $this->driver->getPageSource()); + $this->compatAssertStringContainsString($parentPage, $this->driver->getPageSource()); } public function testShouldSwitchToFrameByElement() @@ -108,7 +108,7 @@ public function testShouldSwitchToFrameByElement() $element = $this->driver->findElement(WebDriverBy::id('iframe_content')); $this->driver->switchTo()->frame($element); - $this->assertContains('This is the content of the iFrame', $this->driver->getPageSource()); + $this->compatAssertStringContainsString('This is the content of the iFrame', $this->driver->getPageSource()); } /** @@ -139,6 +139,6 @@ public function testShouldAcceptStringAsFrameIdInJsonWireMode() $this->driver->switchTo()->frame('iframe_content'); - $this->assertContains('This is the content of the iFrame', $this->driver->getPageSource()); + $this->compatAssertStringContainsString('This is the content of the iFrame', $this->driver->getPageSource()); } } diff --git a/tests/functional/RemoteWebDriverCreateTest.php b/tests/functional/RemoteWebDriverCreateTest.php index db379964d..29302e16a 100644 --- a/tests/functional/RemoteWebDriverCreateTest.php +++ b/tests/functional/RemoteWebDriverCreateTest.php @@ -32,7 +32,7 @@ public function testShouldStartBrowserAndCreateInstanceOfRemoteWebDriver() $this->assertInstanceOf(HttpCommandExecutor::class, $this->driver->getCommandExecutor()); $this->assertNotEmpty($this->driver->getCommandExecutor()->getAddressOfRemoteServer()); - $this->assertInternalType('string', $this->driver->getSessionID()); + $this->assertTrue(is_string($this->driver->getSessionID())); $this->assertNotEmpty($this->driver->getSessionID()); $returnedCapabilities = $this->driver->getCapabilities(); @@ -104,7 +104,7 @@ public function testShouldCreateInstanceFromExistingSessionId() $this->requestTimeout ); $originalDriver->get($this->getTestPageUrl('index.html')); - $this->assertContains('/index.html', $originalDriver->getCurrentURL()); + $this->compatAssertStringContainsString('/index.html', $originalDriver->getCurrentURL()); // Store session ID $sessionId = $originalDriver->getSessionID(); @@ -114,7 +114,7 @@ public function testShouldCreateInstanceFromExistingSessionId() $this->driver = RemoteWebDriver::createBySessionID($sessionId, $this->serverUrl, null, null, $isW3cCompliant); // Check we reused the previous instance (window) and it has the same URL - $this->assertContains('/index.html', $this->driver->getCurrentURL()); + $this->compatAssertStringContainsString('/index.html', $this->driver->getCurrentURL()); // Do some interaction with the new driver $this->assertNotEmpty($this->driver->findElement(WebDriverBy::id('id_test'))->getText()); diff --git a/tests/functional/RemoteWebDriverFindElementTest.php b/tests/functional/RemoteWebDriverFindElementTest.php index 4ac265381..5a7d18e70 100644 --- a/tests/functional/RemoteWebDriverFindElementTest.php +++ b/tests/functional/RemoteWebDriverFindElementTest.php @@ -34,7 +34,7 @@ public function testShouldReturnEmptyArrayIfElementsCannotBeFound() $elements = $this->driver->findElements(WebDriverBy::cssSelector('not_existing')); - $this->assertInternalType('array', $elements); + $this->assertTrue(is_array($elements)); $this->assertCount(0, $elements); } @@ -44,7 +44,7 @@ public function testShouldFindMultipleElements() $elements = $this->driver->findElements(WebDriverBy::cssSelector('ul > li')); - $this->assertInternalType('array', $elements); + $this->assertTrue(is_array($elements)); $this->assertCount(5, $elements); $this->assertContainsOnlyInstancesOf(RemoteWebElement::class, $elements); } diff --git a/tests/functional/RemoteWebDriverTest.php b/tests/functional/RemoteWebDriverTest.php index 28b4e52ab..ae289de5d 100644 --- a/tests/functional/RemoteWebDriverTest.php +++ b/tests/functional/RemoteWebDriverTest.php @@ -43,8 +43,8 @@ public function testShouldGetPageSource() $this->driver->get($this->getTestPageUrl('index.html')); $source = $this->driver->getPageSource(); - $this->assertContains('

    ', $source); - $this->assertContains('Welcome to the php-webdriver testing page.', $source); + $this->compatAssertStringContainsString('

    ', $source); + $this->compatAssertStringContainsString('Welcome to the php-webdriver testing page.', $source); } /** @@ -63,7 +63,7 @@ public function testShouldGetSessionId() $sessionId = $this->driver->getSessionID(); - $this->assertInternalType('string', $sessionId); + $this->assertTrue(is_string($sessionId)); $this->assertNotEmpty($sessionId); } @@ -79,7 +79,7 @@ public function testShouldGetAllSessions() $sessions = RemoteWebDriver::getAllSessions($this->serverUrl, 30000); - $this->assertInternalType('array', $sessions); + $this->assertTrue(is_array($sessions)); $this->assertCount(1, $sessions); $this->assertArrayHasKey('capabilities', $sessions[0]); @@ -124,7 +124,7 @@ public function testShouldGetWindowHandles() $windowHandle = $this->driver->getWindowHandle(); $windowHandles = $this->driver->getWindowHandles(); - $this->assertInternalType('string', $windowHandle); + $this->assertTrue(is_string($windowHandle)); $this->assertNotEmpty($windowHandle); $this->assertSame([$windowHandle], $windowHandles); @@ -266,7 +266,7 @@ public function testShouldTakeScreenshot() $outputPng = $this->driver->takeScreenshot(); $image = imagecreatefromstring($outputPng); - $this->assertInternalType('resource', $image); + $this->assertTrue(is_resource($image)); $this->assertGreaterThan(0, imagesx($image)); $this->assertGreaterThan(0, imagesy($image)); @@ -292,7 +292,7 @@ public function testShouldSaveScreenshotToFile() $this->driver->takeScreenshot($screenshotPath); $image = imagecreatefrompng($screenshotPath); - $this->assertInternalType('resource', $image); + $this->assertTrue(is_resource($image)); $this->assertGreaterThan(0, imagesx($image)); $this->assertGreaterThan(0, imagesy($image)); @@ -323,9 +323,9 @@ public function testShouldGetRemoteEndStatus() { $status = $this->driver->getStatus(); - $this->assertInternalType('boolean', $status->isReady()); + $this->assertTrue(is_bool($status->isReady())); $this->assertNotEmpty($status->getMessage()); - $this->assertInternalType('array', $status->getMeta()); + $this->assertTrue(is_array($status->getMeta())); } } diff --git a/tests/functional/RemoteWebElementTest.php b/tests/functional/RemoteWebElementTest.php index 021e6ed1a..21d890ccc 100644 --- a/tests/functional/RemoteWebElementTest.php +++ b/tests/functional/RemoteWebElementTest.php @@ -318,7 +318,7 @@ public function testShouldReturnEmptyArrayIfChildElementsCannotBeFound() $childElements = $element->findElements(WebDriverBy::cssSelector('not_existing')); - $this->assertInternalType('array', $childElements); + $this->assertTrue(is_array($childElements)); $this->assertCount(0, $childElements); } @@ -330,7 +330,7 @@ public function testShouldFindMultipleChildElements() $allElements = $this->driver->findElements(WebDriverBy::cssSelector('li')); $childElements = $element->findElements(WebDriverBy::cssSelector('li')); - $this->assertInternalType('array', $childElements); + $this->assertTrue(is_array($childElements)); $this->assertCount(5, $allElements); // there should be 5
  • elements on page $this->assertCount(3, $childElements); // but we should find only subelements of one