├── .coveralls.yml
├── .php_cs.dist
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── composer.json
├── lib
├── AbstractWebDriverCheckboxOrRadio.php
├── Chrome
│ ├── ChromeDriver.php
│ ├── ChromeDriverService.php
│ └── ChromeOptions.php
├── Cookie.php
├── Exception
│ ├── ElementClickInterceptedException.php
│ ├── ElementNotInteractableException.php
│ ├── ElementNotSelectableException.php
│ ├── ElementNotVisibleException.php
│ ├── ExpectedException.php
│ ├── IMEEngineActivationFailedException.php
│ ├── IMENotAvailableException.php
│ ├── IndexOutOfBoundsException.php
│ ├── InsecureCertificateException.php
│ ├── InvalidArgumentException.php
│ ├── InvalidCookieDomainException.php
│ ├── InvalidCoordinatesException.php
│ ├── InvalidElementStateException.php
│ ├── InvalidSelectorException.php
│ ├── InvalidSessionIdException.php
│ ├── JavascriptErrorException.php
│ ├── MoveTargetOutOfBoundsException.php
│ ├── NoAlertOpenException.php
│ ├── NoCollectionException.php
│ ├── NoScriptResultException.php
│ ├── NoStringException.php
│ ├── NoStringLengthException.php
│ ├── NoStringWrapperException.php
│ ├── NoSuchAlertException.php
│ ├── NoSuchCollectionException.php
│ ├── NoSuchCookieException.php
│ ├── NoSuchDocumentException.php
│ ├── NoSuchDriverException.php
│ ├── NoSuchElementException.php
│ ├── NoSuchFrameException.php
│ ├── NoSuchWindowException.php
│ ├── NullPointerException.php
│ ├── ScriptTimeoutException.php
│ ├── SessionNotCreatedException.php
│ ├── StaleElementReferenceException.php
│ ├── TimeoutException.php
│ ├── UnableToCaptureScreenException.php
│ ├── UnableToSetCookieException.php
│ ├── UnexpectedAlertOpenException.php
│ ├── UnexpectedJavascriptException.php
│ ├── UnexpectedTagNameException.php
│ ├── UnknownCommandException.php
│ ├── UnknownErrorException.php
│ ├── UnknownMethodException.php
│ ├── UnknownServerException.php
│ ├── UnrecognizedExceptionException.php
│ ├── UnsupportedOperationException.php
│ ├── WebDriverCurlException.php
│ ├── WebDriverException.php
│ └── XPathLookupException.php
├── Firefox
│ ├── FirefoxDriver.php
│ ├── FirefoxPreferences.php
│ └── FirefoxProfile.php
├── Interactions
│ ├── Internal
│ │ ├── WebDriverButtonReleaseAction.php
│ │ ├── WebDriverClickAction.php
│ │ ├── WebDriverClickAndHoldAction.php
│ │ ├── WebDriverContextClickAction.php
│ │ ├── WebDriverCoordinates.php
│ │ ├── WebDriverDoubleClickAction.php
│ │ ├── WebDriverKeyDownAction.php
│ │ ├── WebDriverKeyUpAction.php
│ │ ├── WebDriverKeysRelatedAction.php
│ │ ├── WebDriverMouseAction.php
│ │ ├── WebDriverMouseMoveAction.php
│ │ ├── WebDriverMoveToOffsetAction.php
│ │ ├── WebDriverSendKeysAction.php
│ │ └── WebDriverSingleKeyAction.php
│ ├── Touch
│ │ ├── WebDriverDoubleTapAction.php
│ │ ├── WebDriverDownAction.php
│ │ ├── WebDriverFlickAction.php
│ │ ├── WebDriverFlickFromElementAction.php
│ │ ├── WebDriverLongPressAction.php
│ │ ├── WebDriverMoveAction.php
│ │ ├── WebDriverScrollAction.php
│ │ ├── WebDriverScrollFromElementAction.php
│ │ ├── WebDriverTapAction.php
│ │ ├── WebDriverTouchAction.php
│ │ └── WebDriverTouchScreen.php
│ ├── WebDriverActions.php
│ ├── WebDriverCompositeAction.php
│ └── WebDriverTouchActions.php
├── Internal
│ └── WebDriverLocatable.php
├── JavaScriptExecutor.php
├── Net
│ └── URLChecker.php
├── Remote
│ ├── DesiredCapabilities.php
│ ├── DriverCommand.php
│ ├── ExecuteMethod.php
│ ├── FileDetector.php
│ ├── HttpCommandExecutor.php
│ ├── JsonWireCompat.php
│ ├── LocalFileDetector.php
│ ├── RemoteExecuteMethod.php
│ ├── RemoteKeyboard.php
│ ├── RemoteMouse.php
│ ├── RemoteStatus.php
│ ├── RemoteTargetLocator.php
│ ├── RemoteTouchScreen.php
│ ├── RemoteWebDriver.php
│ ├── RemoteWebElement.php
│ ├── Service
│ │ ├── DriverCommandExecutor.php
│ │ └── DriverService.php
│ ├── UselessFileDetector.php
│ ├── WebDriverBrowserType.php
│ ├── WebDriverCapabilityType.php
│ ├── WebDriverCommand.php
│ └── WebDriverResponse.php
├── Support
│ ├── Events
│ │ ├── EventFiringWebDriver.php
│ │ ├── EventFiringWebDriverNavigation.php
│ │ └── EventFiringWebElement.php
│ └── XPathEscaper.php
├── WebDriver.php
├── WebDriverAction.php
├── WebDriverAlert.php
├── WebDriverBy.php
├── WebDriverCapabilities.php
├── WebDriverCheckboxes.php
├── WebDriverCommandExecutor.php
├── WebDriverDimension.php
├── WebDriverDispatcher.php
├── WebDriverElement.php
├── WebDriverEventListener.php
├── WebDriverExpectedCondition.php
├── WebDriverHasInputDevices.php
├── WebDriverKeyboard.php
├── WebDriverKeys.php
├── WebDriverMouse.php
├── WebDriverNavigation.php
├── WebDriverNavigationInterface.php
├── WebDriverOptions.php
├── WebDriverPlatform.php
├── WebDriverPoint.php
├── WebDriverRadios.php
├── WebDriverSearchContext.php
├── WebDriverSelect.php
├── WebDriverSelectInterface.php
├── WebDriverTargetLocator.php
├── WebDriverTimeouts.php
├── WebDriverUpAction.php
├── WebDriverWait.php
└── WebDriverWindow.php
├── logs
└── .gitkeep
└── phpstan.neon
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | coverage_clover: ./logs/coverage-clover.xml
2 | json_path: ./logs/coveralls-upload.json
3 |
--------------------------------------------------------------------------------
/.php_cs.dist:
--------------------------------------------------------------------------------
1 | in([__DIR__ . '/lib', __DIR__ . '/tests']);
5 |
6 | return PhpCsFixer\Config::create()
7 | ->setRules([
8 | '@PSR2' => true,
9 | 'array_syntax' => ['syntax' => 'short'],
10 | 'binary_operator_spaces' => true,
11 | 'blank_line_before_return' => true,
12 | 'cast_spaces' => true,
13 | 'concat_space' => ['spacing' => 'one'],
14 | 'function_typehint_space' => true,
15 | 'general_phpdoc_annotation_remove' => ['author'],
16 | 'implode_call' => true,
17 | 'is_null' => true,
18 | 'linebreak_after_opening_tag' => true,
19 | 'lowercase_cast' => true,
20 | 'mb_str_functions' => true,
21 | 'method_separation' => true,
22 | 'native_function_casing' => true,
23 | 'new_with_braces' => true,
24 | 'no_alias_functions' => true,
25 | 'no_blank_lines_after_class_opening' => true,
26 | 'no_blank_lines_after_phpdoc' => true,
27 | 'no_empty_comment' => true,
28 | 'no_empty_phpdoc' => true,
29 | 'no_empty_statement' => true,
30 | 'no_extra_consecutive_blank_lines' => [
31 | 'use',
32 | 'break',
33 | 'continue',
34 | 'extra',
35 | 'return',
36 | 'throw',
37 | 'useTrait',
38 | 'curly_brace_block',
39 | 'parenthesis_brace_block',
40 | 'square_brace_block',
41 | ],
42 | 'no_leading_import_slash' => true,
43 | 'no_leading_namespace_whitespace' => true,
44 | 'no_singleline_whitespace_before_semicolons' => true,
45 | 'no_trailing_comma_in_singleline_array' => true,
46 | 'no_unreachable_default_argument_value' => true,
47 | 'no_unused_imports' => true,
48 | 'no_useless_else' => true,
49 | 'no_useless_return' => true,
50 | 'no_whitespace_in_blank_line' => true,
51 | 'object_operator_without_whitespace' => true,
52 | 'ordered_class_elements' => true,
53 | 'ordered_imports' => true,
54 | 'php_unit_construct' => true,
55 | 'php_unit_dedicate_assert' => true,
56 | 'php_unit_expectation' => ['target' => '5.6'],
57 | 'php_unit_method_casing' => ['case' => 'camel_case'],
58 | 'php_unit_mock' => true,
59 | 'php_unit_mock_short_will_return' => true,
60 | 'php_unit_namespaced' => ['target' => '5.7'],
61 | 'php_unit_no_expectation_annotation' => true,
62 | 'php_unit_ordered_covers' => true,
63 | 'php_unit_set_up_tear_down_visibility' => true,
64 | 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'],
65 | 'phpdoc_add_missing_param_annotation' => true,
66 | 'phpdoc_indent' => true,
67 | 'phpdoc_no_access' => true,
68 | 'phpdoc_no_empty_return' => true,
69 | 'phpdoc_no_package' => true,
70 | 'phpdoc_order' => true,
71 | 'phpdoc_scalar' => true,
72 | 'phpdoc_single_line_var_spacing' => true,
73 | 'phpdoc_trim' => true,
74 | 'phpdoc_types' => true,
75 | 'psr4' => true,
76 | 'self_accessor' => true,
77 | 'short_scalar_cast' => true,
78 | 'single_blank_line_before_namespace' => true,
79 | 'single_quote' => true,
80 | 'space_after_semicolon' => true,
81 | 'standardize_not_equals' => true,
82 | 'ternary_operator_spaces' => true,
83 | 'trailing_comma_in_multiline_array' => true,
84 | 'trim_array_spaces' => true,
85 | 'unary_operator_spaces' => true,
86 | 'visibility_required' => true,
87 | 'whitespace_after_comma_in_array' => true,
88 | 'yoda_style' => false,
89 | ])
90 | ->setRiskyAllowed(true)
91 | ->setFinder($finder);
92 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to php-webdriver
2 |
3 | We love to have your help to make php-webdriver better!
4 |
5 | Feel free to open an [issue](https://github.com/facebook/php-webdriver/issues) if you run into any problem, or
6 | send a pull request (see bellow) with your contribution.
7 |
8 | ## Code of Conduct
9 | The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md)
10 |
11 | ## Workflow when contributing a patch
12 |
13 | 1. Fork the project on GitHub
14 | 2. Implement your code changes into separate branch
15 | 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.
16 | 4. When implementing notable change, fix or a new feature, add record to Unreleased section of [CHANGELOG.md](CHANGELOG.md)
17 | 5. Submit your [pull request](https://github.com/facebook/php-webdriver/pulls) against community branch
18 |
19 | Note before any pull request can be accepted, a [Contributors Licensing Agreement](https://developers.facebook.com/opensource/cla) must be signed.
20 |
21 | 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#.
22 | FYI, here is the overview of [the official Java API](http://seleniumhq.github.io/selenium/docs/api/java/)
23 |
24 | ### Run unit tests
25 |
26 | There are two test-suites: one with unit tests only, second with functional tests, which require running selenium server.
27 |
28 | To execute all tests simply run:
29 |
30 | ./vendor/bin/phpunit
31 |
32 | If you want to execute just the unit tests, run:
33 |
34 | ./vendor/bin/phpunit --testsuite unit
35 |
36 | For the functional tests you must first [download](http://selenium-release.storage.googleapis.com/index.html) and start
37 | the selenium standalone server, start the local PHP server which will serve the test pages and then run the `functional`
38 | test suite:
39 |
40 | java -jar selenium-server-standalone-3.9.1.jar -log selenium.log &
41 | php -S localhost:8000 -t tests/functional/web/ &
42 | ./vendor/bin/phpunit --testsuite functional
43 |
44 | The functional tests will be started in HtmlUnit headless browser by default. If you want to run them in eg. Firefox,
45 | simply set the `BROWSER_NAME` environment variable:
46 |
47 | ...
48 | export BROWSER_NAME="firefox"
49 | ./vendor/bin/phpunit --testsuite functional
50 |
51 | To test with Geckodriver, [download](https://github.com/mozilla/geckodriver/releases) and start the server, then run:
52 |
53 | export GECKODRIVER=1
54 | export BROWSER_NAME=firefox
55 | ./vendor/bin/phpunit --testsuite functional
56 |
57 | ### Check coding style
58 |
59 | Your code-style should comply with [PSR-2](http://www.php-fig.org/psr/psr-2/). To make sure your code matches this requirement run:
60 |
61 | composer codestyle:check
62 |
63 | To auto-fix the codestyle simply run:
64 |
65 | composer codestyle:fix
66 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### What are you trying to achieve? (Expected behavior)
2 |
3 |
4 | ### What do you get instead? (Actual behavior)
5 |
6 |
7 | ### How could the issue be reproduced? (Steps to reproduce)
8 |
9 |
10 | ```php
11 | // You can insert your PHP code here (or remove this block if it is not relevant for the issue).
12 | ```
13 |
14 | ### Details
15 |
16 |
17 | * Php-webdriver version:
18 | * PHP version:
19 | * Selenium server version:
20 | * Operating system:
21 | * Browser used + version:
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "facebook/webdriver",
3 | "description": "A PHP client for Selenium WebDriver",
4 | "keywords": ["webdriver", "selenium", "php", "facebook"],
5 | "homepage": "https://github.com/facebook/php-webdriver",
6 | "type": "library",
7 | "license": "Apache-2.0",
8 | "support": {
9 | "issues": "https://github.com/facebook/php-webdriver/issues",
10 | "forum": "https://www.facebook.com/groups/phpwebdriver/",
11 | "source": "https://github.com/facebook/php-webdriver"
12 | },
13 | "minimum-stability": "beta",
14 | "require": {
15 | "php": "^5.6 || ~7.0",
16 | "ext-curl": "*",
17 | "ext-json": "*",
18 | "ext-zip": "*",
19 | "symfony/polyfill-mbstring": "^1.12",
20 | "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0"
21 | },
22 | "require-dev": {
23 | "friendsofphp/php-cs-fixer": "^2.0",
24 | "jakub-onderka/php-parallel-lint": "^1.0",
25 | "php-coveralls/php-coveralls": "^2.0",
26 | "php-mock/php-mock-phpunit": "^1.1",
27 | "phpunit/phpunit": "^5.7",
28 | "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0",
29 | "sminnee/phpunit-mock-objects": "^3.4",
30 | "squizlabs/php_codesniffer": "^3.5",
31 | "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0"
32 | },
33 | "suggest": {
34 | "ext-SimpleXML": "For Firefox profile creation"
35 | },
36 | "autoload": {
37 | "files": [
38 | "lib/Exception/TimeoutException.php"
39 | ],
40 | "psr-4": {
41 | "Facebook\\WebDriver\\": "lib/"
42 | }
43 | },
44 | "autoload-dev": {
45 | "psr-4": {
46 | "Facebook\\WebDriver\\": ["tests/unit", "tests/functional"]
47 | },
48 | "classmap": ["tests/functional/"]
49 | },
50 | "scripts": {
51 | "codestyle:check": [
52 | "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff --dry-run -vvv --ansi",
53 | "vendor/bin/phpcs --standard=PSR2 ./lib/ ./tests/"
54 | ],
55 | "codestyle:fix": [
56 | "vendor/bin/php-cs-fixer fix --diff --diff-format=udiff -vvv || exit 0",
57 | "vendor/bin/phpcbf --standard=PSR2 ./lib/ ./tests/"
58 | ],
59 | "analyze": [
60 | "vendor/bin/parallel-lint -j 10 ./lib ./tests",
61 | "vendor/bin/phpstan.phar analyze ./lib ./tests --level 2 -c phpstan.neon --ansi"
62 | ]
63 | },
64 | "config": {
65 | "sort-packages": true
66 | },
67 | "extra": {
68 | "branch-alias": {
69 | "dev-community": "1.8.x-dev"
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/Chrome/ChromeDriver.php:
--------------------------------------------------------------------------------
1 | startSession($desired_capabilities);
41 |
42 | return $driver;
43 | }
44 |
45 | public function startSession(DesiredCapabilities $desired_capabilities)
46 | {
47 | $command = new WebDriverCommand(
48 | null,
49 | DriverCommand::NEW_SESSION,
50 | [
51 | 'desiredCapabilities' => $desired_capabilities->toArray(),
52 | ]
53 | );
54 | $response = $this->executor->execute($command);
55 | $this->sessionID = $response->getSessionID();
56 | }
57 |
58 | /**
59 | * Always throws an exception. Use ChromeDriver::start() instead.
60 | *
61 | * @param string $selenium_server_url
62 | * @param DesiredCapabilities|array $desired_capabilities
63 | * @param int|null $connection_timeout_in_ms
64 | * @param int|null $request_timeout_in_ms
65 | * @param string|null $http_proxy
66 | * @param int|null $http_proxy_port
67 | * @param DesiredCapabilities $required_capabilities
68 | * @throws WebDriverException
69 | * @return RemoteWebDriver
70 | */
71 | public static function create(
72 | $selenium_server_url = 'http://localhost:4444/wd/hub',
73 | $desired_capabilities = null,
74 | $connection_timeout_in_ms = null,
75 | $request_timeout_in_ms = null,
76 | $http_proxy = null,
77 | $http_proxy_port = null,
78 | DesiredCapabilities $required_capabilities = null
79 | ) {
80 | throw new WebDriverException('Please use ChromeDriver::start() instead.');
81 | }
82 |
83 | /**
84 | * Always throws an exception. Use ChromeDriver::start() instead.
85 | *
86 | * @param string $session_id The existing session id
87 | * @param string $selenium_server_url The url of the remote Selenium WebDriver server
88 | * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server
89 | * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server
90 | * @throws WebDriverException
91 | * @return RemoteWebDriver|void
92 | */
93 | public static function createBySessionID(
94 | $session_id,
95 | $selenium_server_url = 'http://localhost:4444/wd/hub',
96 | $connection_timeout_in_ms = null,
97 | $request_timeout_in_ms = null
98 | ) {
99 | throw new WebDriverException('Please use ChromeDriver::start() instead.');
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/lib/Chrome/ChromeDriverService.php:
--------------------------------------------------------------------------------
1 | mouse->mouseUp($this->getActionLocation());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverClickAction.php:
--------------------------------------------------------------------------------
1 | mouse->click($this->getActionLocation());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverClickAndHoldAction.php:
--------------------------------------------------------------------------------
1 | mouse->mouseDown($this->getActionLocation());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverContextClickAction.php:
--------------------------------------------------------------------------------
1 | mouse->contextClick($this->getActionLocation());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverCoordinates.php:
--------------------------------------------------------------------------------
1 | onScreen = $on_screen;
52 | $this->inViewPort = $in_view_port;
53 | $this->onPage = $on_page;
54 | $this->auxiliary = $auxiliary;
55 | }
56 |
57 | /**
58 | * @throws UnsupportedOperationException
59 | * @return WebDriverPoint
60 | */
61 | public function onScreen()
62 | {
63 | throw new UnsupportedOperationException(
64 | 'onScreen is planned but not yet supported by Selenium'
65 | );
66 | }
67 |
68 | /**
69 | * @return WebDriverPoint
70 | */
71 | public function inViewPort()
72 | {
73 | return call_user_func($this->inViewPort);
74 | }
75 |
76 | /**
77 | * @return WebDriverPoint
78 | */
79 | public function onPage()
80 | {
81 | return call_user_func($this->onPage);
82 | }
83 |
84 | /**
85 | * @return string The attached object id.
86 | */
87 | public function getAuxiliary()
88 | {
89 | return $this->auxiliary;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverDoubleClickAction.php:
--------------------------------------------------------------------------------
1 | mouse->doubleClick($this->getActionLocation());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverKeyDownAction.php:
--------------------------------------------------------------------------------
1 | focusOnElement();
25 | $this->keyboard->pressKey($this->key);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverKeyUpAction.php:
--------------------------------------------------------------------------------
1 | focusOnElement();
25 | $this->keyboard->releaseKey($this->key);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverKeysRelatedAction.php:
--------------------------------------------------------------------------------
1 | keyboard = $keyboard;
51 | $this->mouse = $mouse;
52 | $this->locationProvider = $location_provider;
53 | }
54 |
55 | protected function focusOnElement()
56 | {
57 | if ($this->locationProvider) {
58 | $this->mouse->click($this->locationProvider->getCoordinates());
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverMouseAction.php:
--------------------------------------------------------------------------------
1 | mouse = $mouse;
42 | $this->locationProvider = $location_provider;
43 | }
44 |
45 | /**
46 | * @return null|WebDriverCoordinates
47 | */
48 | protected function getActionLocation()
49 | {
50 | if ($this->locationProvider !== null) {
51 | return $this->locationProvider->getCoordinates();
52 | }
53 |
54 | return null;
55 | }
56 |
57 | protected function moveToLocation()
58 | {
59 | $this->mouse->mouseMove($this->locationProvider);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverMouseMoveAction.php:
--------------------------------------------------------------------------------
1 | mouse->mouseMove($this->getActionLocation());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php:
--------------------------------------------------------------------------------
1 | xOffset = $x_offset;
47 | $this->yOffset = $y_offset;
48 | }
49 |
50 | public function perform()
51 | {
52 | $this->mouse->mouseMove(
53 | $this->getActionLocation(),
54 | $this->xOffset,
55 | $this->yOffset
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverSendKeysAction.php:
--------------------------------------------------------------------------------
1 | keys = $keys;
44 | }
45 |
46 | public function perform()
47 | {
48 | $this->focusOnElement();
49 | $this->keyboard->sendKeys($this->keys);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/Interactions/Internal/WebDriverSingleKeyAction.php:
--------------------------------------------------------------------------------
1 | key = $key;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverDoubleTapAction.php:
--------------------------------------------------------------------------------
1 | touchScreen->doubleTap($this->locationProvider);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverDownAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
39 | $this->y = $y;
40 | parent::__construct($touch_screen);
41 | }
42 |
43 | public function perform()
44 | {
45 | $this->touchScreen->down($this->x, $this->y);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverFlickAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
39 | $this->y = $y;
40 | parent::__construct($touch_screen);
41 | }
42 |
43 | public function perform()
44 | {
45 | $this->touchScreen->flick($this->x, $this->y);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverFlickFromElementAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
51 | $this->y = $y;
52 | $this->speed = $speed;
53 | parent::__construct($touch_screen, $element);
54 | }
55 |
56 | public function perform()
57 | {
58 | $this->touchScreen->flickFromElement(
59 | $this->locationProvider,
60 | $this->x,
61 | $this->y,
62 | $this->speed
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverLongPressAction.php:
--------------------------------------------------------------------------------
1 | touchScreen->longPress($this->locationProvider);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverMoveAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
33 | $this->y = $y;
34 | parent::__construct($touch_screen);
35 | }
36 |
37 | public function perform()
38 | {
39 | $this->touchScreen->move($this->x, $this->y);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverScrollAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
33 | $this->y = $y;
34 | parent::__construct($touch_screen);
35 | }
36 |
37 | public function perform()
38 | {
39 | $this->touchScreen->scroll($this->x, $this->y);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverScrollFromElementAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
39 | $this->y = $y;
40 | parent::__construct($touch_screen, $element);
41 | }
42 |
43 | public function perform()
44 | {
45 | $this->touchScreen->scrollFromElement(
46 | $this->locationProvider,
47 | $this->x,
48 | $this->y
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverTapAction.php:
--------------------------------------------------------------------------------
1 | touchScreen->tap($this->locationProvider);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverTouchAction.php:
--------------------------------------------------------------------------------
1 | touchScreen = $touch_screen;
44 | $this->locationProvider = $location_provider;
45 | }
46 |
47 | /**
48 | * @return null|WebDriverCoordinates
49 | */
50 | protected function getActionLocation()
51 | {
52 | return $this->locationProvider !== null
53 | ? $this->locationProvider->getCoordinates() : null;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/Interactions/Touch/WebDriverTouchScreen.php:
--------------------------------------------------------------------------------
1 | actions[] = $action;
39 |
40 | return $this;
41 | }
42 |
43 | /**
44 | * Get the number of actions in the sequence.
45 | *
46 | * @return int The number of actions.
47 | */
48 | public function getNumberOfActions()
49 | {
50 | return count($this->actions);
51 | }
52 |
53 | /**
54 | * Perform the sequence of actions.
55 | */
56 | public function perform()
57 | {
58 | foreach ($this->actions as $action) {
59 | $action->perform();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/Internal/WebDriverLocatable.php:
--------------------------------------------------------------------------------
1 | microtime(true)) {
31 | if ($this->getHTTPResponseCode($url) === 200) {
32 | return $this;
33 | }
34 | usleep(self::POLL_INTERVAL_MS);
35 | }
36 |
37 | throw new TimeoutException(sprintf(
38 | 'Timed out waiting for %s to become available after %d ms.',
39 | $url,
40 | $timeout_in_ms
41 | ));
42 | }
43 |
44 | public function waitUntilUnavailable($timeout_in_ms, $url)
45 | {
46 | $end = microtime(true) + $timeout_in_ms / 1000;
47 |
48 | while ($end > microtime(true)) {
49 | if ($this->getHTTPResponseCode($url) !== 200) {
50 | return $this;
51 | }
52 | usleep(self::POLL_INTERVAL_MS);
53 | }
54 |
55 | throw new TimeoutException(sprintf(
56 | 'Timed out waiting for %s to become unavailable after %d ms.',
57 | $url,
58 | $timeout_in_ms
59 | ));
60 | }
61 |
62 | private function getHTTPResponseCode($url)
63 | {
64 | $ch = curl_init();
65 | curl_setopt($ch, CURLOPT_URL, $url);
66 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
67 | // The PHP doc indicates that CURLOPT_CONNECTTIMEOUT_MS constant is added in cURL 7.16.2
68 | // available since PHP 5.2.3.
69 | if (!defined('CURLOPT_CONNECTTIMEOUT_MS')) {
70 | define('CURLOPT_CONNECTTIMEOUT_MS', 156); // default value for CURLOPT_CONNECTTIMEOUT_MS
71 | }
72 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS);
73 |
74 | $code = null;
75 | try {
76 | curl_exec($ch);
77 | $info = curl_getinfo($ch);
78 | $code = $info['http_code'];
79 | } catch (Exception $e) {
80 | }
81 | curl_close($ch);
82 |
83 | return $code;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/Remote/ExecuteMethod.php:
--------------------------------------------------------------------------------
1 | getMechanism();
54 | $value = $by->getValue();
55 |
56 | if ($isW3cCompliant) {
57 | switch ($mechanism) {
58 | // Convert to CSS selectors
59 | case 'class name':
60 | $mechanism = 'css selector';
61 | $value = sprintf('.%s', self::escapeSelector($value));
62 | break;
63 | case 'id':
64 | $mechanism = 'css selector';
65 | $value = sprintf('#%s', self::escapeSelector($value));
66 | break;
67 | case 'name':
68 | $mechanism = 'css selector';
69 | $value = sprintf('[name=\'%s\']', self::escapeSelector($value));
70 | break;
71 | }
72 | }
73 |
74 | return ['using' => $mechanism, 'value' => $value];
75 | }
76 |
77 | /**
78 | * Escapes a CSS selector.
79 | *
80 | * Code adapted from the Zend Escaper project.
81 | *
82 | * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
83 | * @see https://github.com/zendframework/zend-escaper/blob/master/src/Escaper.php
84 | *
85 | * @param string $selector
86 | * @return string
87 | */
88 | private static function escapeSelector($selector)
89 | {
90 | return preg_replace_callback('/[^a-z0-9]/iSu', function ($matches) {
91 | $chr = $matches[0];
92 | if (mb_strlen($chr) === 1) {
93 | $ord = ord($chr);
94 | } else {
95 | $chr = mb_convert_encoding($chr, 'UTF-32BE', 'UTF-8');
96 | $ord = hexdec(bin2hex($chr));
97 | }
98 |
99 | return sprintf('\\%X ', $ord);
100 | }, $selector);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/lib/Remote/LocalFileDetector.php:
--------------------------------------------------------------------------------
1 | driver = $driver;
31 | }
32 |
33 | /**
34 | * @param string $command_name
35 | * @param array $parameters
36 | * @return mixed
37 | */
38 | public function execute($command_name, array $parameters = [])
39 | {
40 | return $this->driver->execute($command_name, $parameters);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/Remote/RemoteKeyboard.php:
--------------------------------------------------------------------------------
1 | executor = $executor;
40 | $this->driver = $driver;
41 | $this->isW3cCompliant = $isW3cCompliant;
42 | }
43 |
44 | /**
45 | * Send keys to active element
46 | * @param string|array $keys
47 | * @return $this
48 | */
49 | public function sendKeys($keys)
50 | {
51 | if ($this->isW3cCompliant) {
52 | $activeElement = $this->driver->switchTo()->activeElement();
53 | $activeElement->sendKeys($keys);
54 | } else {
55 | $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
56 | 'value' => WebDriverKeys::encode($keys),
57 | ]);
58 | }
59 |
60 | return $this;
61 | }
62 |
63 | /**
64 | * Press a modifier key
65 | *
66 | * @see WebDriverKeys
67 | * @param string $key
68 | * @return $this
69 | */
70 | public function pressKey($key)
71 | {
72 | if ($this->isW3cCompliant) {
73 | $this->executor->execute(DriverCommand::ACTIONS, [
74 | 'actions' => [
75 | [
76 | 'type' => 'key',
77 | 'id' => 'keyboard',
78 | 'actions' => [['type' => 'keyDown', 'value' => $key]],
79 | ],
80 | ],
81 | ]);
82 | } else {
83 | $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
84 | 'value' => [(string) $key],
85 | ]);
86 | }
87 |
88 | return $this;
89 | }
90 |
91 | /**
92 | * Release a modifier key
93 | *
94 | * @see WebDriverKeys
95 | * @param string $key
96 | * @return $this
97 | */
98 | public function releaseKey($key)
99 | {
100 | if ($this->isW3cCompliant) {
101 | $this->executor->execute(DriverCommand::ACTIONS, [
102 | 'actions' => [
103 | [
104 | 'type' => 'key',
105 | 'id' => 'keyboard',
106 | 'actions' => [['type' => 'keyUp', 'value' => $key]],
107 | ],
108 | ],
109 | ]);
110 | } else {
111 | $this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
112 | 'value' => [(string) $key],
113 | ]);
114 | }
115 |
116 | return $this;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/lib/Remote/RemoteStatus.php:
--------------------------------------------------------------------------------
1 | isReady = (bool) $isReady;
39 | $this->message = (string) $message;
40 |
41 | $this->setMeta($meta);
42 | }
43 |
44 | /**
45 | * @param array $responseBody
46 | * @return RemoteStatus
47 | */
48 | public static function createFromResponse(array $responseBody)
49 | {
50 | $object = new static($responseBody['ready'], $responseBody['message'], $responseBody);
51 |
52 | return $object;
53 | }
54 |
55 | /**
56 | * The remote end's readiness state.
57 | * False if an attempt to create a session at the current time would fail.
58 | * However, the value true does not guarantee that a New Session command will succeed.
59 | *
60 | * @return bool
61 | */
62 | public function isReady()
63 | {
64 | return $this->isReady;
65 | }
66 |
67 | /**
68 | * An implementation-defined string explaining the remote end's readiness state.
69 | *
70 | * @return string
71 | */
72 | public function getMessage()
73 | {
74 | return $this->message;
75 | }
76 |
77 | /**
78 | * Arbitrary meta information specific to remote-end implementation.
79 | *
80 | * @return array
81 | */
82 | public function getMeta()
83 | {
84 | return $this->meta;
85 | }
86 |
87 | protected function setMeta(array $meta)
88 | {
89 | unset($meta['ready'], $meta['message']);
90 |
91 | $this->meta = $meta;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lib/Remote/Service/DriverCommandExecutor.php:
--------------------------------------------------------------------------------
1 | getURL());
38 | $this->service = $service;
39 | }
40 |
41 | /**
42 | * @param WebDriverCommand $command
43 | *
44 | * @throws WebDriverException
45 | * @throws \Exception
46 | * @return WebDriverResponse
47 | */
48 | public function execute(WebDriverCommand $command)
49 | {
50 | if ($command->getName() === DriverCommand::NEW_SESSION) {
51 | $this->service->start();
52 | }
53 |
54 | try {
55 | $value = parent::execute($command);
56 | if ($command->getName() === DriverCommand::QUIT) {
57 | $this->service->stop();
58 | }
59 |
60 | return $value;
61 | } catch (\Exception $e) {
62 | if (!$this->service->isRunning()) {
63 | throw new WebDriverException('The driver server has died.');
64 | }
65 | throw $e;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/Remote/Service/DriverService.php:
--------------------------------------------------------------------------------
1 | executable = self::checkExecutable($executable);
62 | $this->url = sprintf('http://localhost:%d', $port);
63 | $this->args = $args;
64 | $this->environment = $environment ?: $_ENV;
65 | }
66 |
67 | /**
68 | * @return string
69 | */
70 | public function getURL()
71 | {
72 | return $this->url;
73 | }
74 |
75 | /**
76 | * @return DriverService
77 | */
78 | public function start()
79 | {
80 | if ($this->process !== null) {
81 | return $this;
82 | }
83 |
84 | $this->process = $this->createProcess();
85 | $this->process->start();
86 |
87 | $checker = new URLChecker();
88 | $checker->waitUntilAvailable(20 * 1000, $this->url . '/status');
89 |
90 | return $this;
91 | }
92 |
93 | /**
94 | * @return DriverService
95 | */
96 | public function stop()
97 | {
98 | if ($this->process === null) {
99 | return $this;
100 | }
101 |
102 | $this->process->stop();
103 | $this->process = null;
104 |
105 | $checker = new URLChecker();
106 | $checker->waitUntilUnavailable(3 * 1000, $this->url . '/shutdown');
107 |
108 | return $this;
109 | }
110 |
111 | /**
112 | * @return bool
113 | */
114 | public function isRunning()
115 | {
116 | if ($this->process === null) {
117 | return false;
118 | }
119 |
120 | return $this->process->isRunning();
121 | }
122 |
123 | /**
124 | * Check if the executable is executable.
125 | *
126 | * @param string $executable
127 | * @throws Exception
128 | * @return string
129 | */
130 | protected static function checkExecutable($executable)
131 | {
132 | if (!is_file($executable)) {
133 | throw new Exception("'$executable' is not a file.");
134 | }
135 |
136 | if (!is_executable($executable)) {
137 | throw new Exception("'$executable' is not executable.");
138 | }
139 |
140 | return $executable;
141 | }
142 |
143 | /**
144 | * @return Process
145 | */
146 | private function createProcess()
147 | {
148 | // BC: ProcessBuilder deprecated since Symfony 3.4 and removed in Symfony 4.0.
149 | if (class_exists(ProcessBuilder::class)
150 | && false === mb_strpos('@deprecated', (new \ReflectionClass(ProcessBuilder::class))->getDocComment())
151 | ) {
152 | $processBuilder = (new ProcessBuilder())
153 | ->setPrefix($this->executable)
154 | ->setArguments($this->args)
155 | ->addEnvironmentVariables($this->environment);
156 |
157 | return $processBuilder->getProcess();
158 | }
159 | // Safe to use since Symfony 3.3
160 | $commandLine = array_merge([$this->executable], $this->args);
161 |
162 | return new Process($commandLine, null, $this->environment);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/lib/Remote/UselessFileDetector.php:
--------------------------------------------------------------------------------
1 | sessionID = $session_id;
36 | $this->name = $name;
37 | $this->parameters = $parameters;
38 | }
39 |
40 | /**
41 | * @return string
42 | */
43 | public function getName()
44 | {
45 | return $this->name;
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | public function getSessionID()
52 | {
53 | return $this->sessionID;
54 | }
55 |
56 | /**
57 | * @return array
58 | */
59 | public function getParameters()
60 | {
61 | return $this->parameters;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/Remote/WebDriverResponse.php:
--------------------------------------------------------------------------------
1 | sessionID = $session_id;
39 | }
40 |
41 | /**
42 | * @return null|int
43 | */
44 | public function getStatus()
45 | {
46 | return $this->status;
47 | }
48 |
49 | /**
50 | * @param int $status
51 | * @return WebDriverResponse
52 | */
53 | public function setStatus($status)
54 | {
55 | $this->status = $status;
56 |
57 | return $this;
58 | }
59 |
60 | /**
61 | * @return mixed
62 | */
63 | public function getValue()
64 | {
65 | return $this->value;
66 | }
67 |
68 | /**
69 | * @param mixed $value
70 | * @return WebDriverResponse
71 | */
72 | public function setValue($value)
73 | {
74 | $this->value = $value;
75 |
76 | return $this;
77 | }
78 |
79 | /**
80 | * @return null|string
81 | */
82 | public function getSessionID()
83 | {
84 | return $this->sessionID;
85 | }
86 |
87 | /**
88 | * @param mixed $session_id
89 | * @return WebDriverResponse
90 | */
91 | public function setSessionID($session_id)
92 | {
93 | $this->sessionID = $session_id;
94 |
95 | return $this;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/lib/Support/Events/EventFiringWebDriverNavigation.php:
--------------------------------------------------------------------------------
1 | navigator = $navigator;
40 | $this->dispatcher = $dispatcher;
41 | }
42 |
43 | /**
44 | * @return WebDriverDispatcher
45 | */
46 | public function getDispatcher()
47 | {
48 | return $this->dispatcher;
49 | }
50 |
51 | /**
52 | * @return WebDriverNavigationInterface
53 | */
54 | public function getNavigator()
55 | {
56 | return $this->navigator;
57 | }
58 |
59 | public function back()
60 | {
61 | $this->dispatch(
62 | 'beforeNavigateBack',
63 | $this->getDispatcher()->getDefaultDriver()
64 | );
65 | try {
66 | $this->navigator->back();
67 | } catch (WebDriverException $exception) {
68 | $this->dispatchOnException($exception);
69 | }
70 | $this->dispatch(
71 | 'afterNavigateBack',
72 | $this->getDispatcher()->getDefaultDriver()
73 | );
74 |
75 | return $this;
76 | }
77 |
78 | public function forward()
79 | {
80 | $this->dispatch(
81 | 'beforeNavigateForward',
82 | $this->getDispatcher()->getDefaultDriver()
83 | );
84 | try {
85 | $this->navigator->forward();
86 | } catch (WebDriverException $exception) {
87 | $this->dispatchOnException($exception);
88 | }
89 | $this->dispatch(
90 | 'afterNavigateForward',
91 | $this->getDispatcher()->getDefaultDriver()
92 | );
93 |
94 | return $this;
95 | }
96 |
97 | public function refresh()
98 | {
99 | try {
100 | $this->navigator->refresh();
101 |
102 | return $this;
103 | } catch (WebDriverException $exception) {
104 | $this->dispatchOnException($exception);
105 | throw $exception;
106 | }
107 | }
108 |
109 | public function to($url)
110 | {
111 | $this->dispatch(
112 | 'beforeNavigateTo',
113 | $url,
114 | $this->getDispatcher()->getDefaultDriver()
115 | );
116 |
117 | try {
118 | $this->navigator->to($url);
119 | } catch (WebDriverException $exception) {
120 | $this->dispatchOnException($exception);
121 | throw $exception;
122 | }
123 |
124 | $this->dispatch(
125 | 'afterNavigateTo',
126 | $url,
127 | $this->getDispatcher()->getDefaultDriver()
128 | );
129 |
130 | return $this;
131 | }
132 |
133 | /**
134 | * @param mixed $method
135 | * @param mixed ...$arguments
136 | */
137 | protected function dispatch($method, ...$arguments)
138 | {
139 | if (!$this->dispatcher) {
140 | return;
141 | }
142 |
143 | $this->dispatcher->dispatch($method, $arguments);
144 | }
145 |
146 | /**
147 | * @param WebDriverException $exception
148 | */
149 | protected function dispatchOnException(WebDriverException $exception)
150 | {
151 | $this->dispatch('onException', $exception);
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/lib/Support/XPathEscaper.php:
--------------------------------------------------------------------------------
1 | `concat('foo', "'" ,'"bar')`
23 | *
24 | * @param string $xpathToEscape The xpath to be converted.
25 | * @return string The escaped string.
26 | */
27 | public static function escapeQuotes($xpathToEscape)
28 | {
29 | // Single quotes not present => we can quote in them
30 | if (mb_strpos($xpathToEscape, "'") === false) {
31 | return sprintf("'%s'", $xpathToEscape);
32 | }
33 |
34 | // Double quotes not present => we can quote in them
35 | if (mb_strpos($xpathToEscape, '"') === false) {
36 | return sprintf('"%s"', $xpathToEscape);
37 | }
38 |
39 | // Both single and double quotes are present
40 | return sprintf(
41 | "concat('%s')",
42 | str_replace("'", "', \"'\" ,'", $xpathToEscape)
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/WebDriver.php:
--------------------------------------------------------------------------------
1 | wait(20, 1000)->until(
94 | * WebDriverExpectedCondition::titleIs('WebDriver Page')
95 | * );
96 | *
97 | * @param int $timeout_in_second
98 | * @param int $interval_in_millisecond
99 | * @return WebDriverWait
100 | */
101 | public function wait(
102 | $timeout_in_second = 30,
103 | $interval_in_millisecond = 250
104 | );
105 |
106 | /**
107 | * An abstraction for managing stuff you would do in a browser menu. For
108 | * example, adding and deleting cookies.
109 | *
110 | * @return WebDriverOptions
111 | */
112 | public function manage();
113 |
114 | /**
115 | * An abstraction allowing the driver to access the browser's history and to
116 | * navigate to a given URL.
117 | *
118 | * @return WebDriverNavigationInterface
119 | * @see WebDriverNavigation
120 | */
121 | public function navigate();
122 |
123 | /**
124 | * Switch to a different window or frame.
125 | *
126 | * @return WebDriverTargetLocator
127 | * @see WebDriverTargetLocator
128 | */
129 | public function switchTo();
130 |
131 | // TODO: Add in next major release (BC)
132 | ///**
133 | // * @return WebDriverTouchScreen
134 | // */
135 | //public function getTouch();
136 |
137 | /**
138 | * @param string $name
139 | * @param array $params
140 | * @return mixed
141 | */
142 | public function execute($name, $params);
143 | }
144 |
--------------------------------------------------------------------------------
/lib/WebDriverAction.php:
--------------------------------------------------------------------------------
1 | executor = $executor;
34 | }
35 |
36 | /**
37 | * Accept alert
38 | *
39 | * @return WebDriverAlert The instance.
40 | */
41 | public function accept()
42 | {
43 | $this->executor->execute(DriverCommand::ACCEPT_ALERT);
44 |
45 | return $this;
46 | }
47 |
48 | /**
49 | * Dismiss alert
50 | *
51 | * @return WebDriverAlert The instance.
52 | */
53 | public function dismiss()
54 | {
55 | $this->executor->execute(DriverCommand::DISMISS_ALERT);
56 |
57 | return $this;
58 | }
59 |
60 | /**
61 | * Get alert text
62 | *
63 | * @return string
64 | */
65 | public function getText()
66 | {
67 | return $this->executor->execute(DriverCommand::GET_ALERT_TEXT);
68 | }
69 |
70 | /**
71 | * Send keystrokes to javascript prompt() dialog
72 | *
73 | * @param string $value
74 | * @return WebDriverAlert
75 | */
76 | public function sendKeys($value)
77 | {
78 | $this->executor->execute(
79 | DriverCommand::SET_ALERT_VALUE,
80 | ['text' => $value]
81 | );
82 |
83 | return $this;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/WebDriverBy.php:
--------------------------------------------------------------------------------
1 | mechanism = $mechanism;
39 | $this->value = $value;
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function getMechanism()
46 | {
47 | return $this->mechanism;
48 | }
49 |
50 | /**
51 | * @return string
52 | */
53 | public function getValue()
54 | {
55 | return $this->value;
56 | }
57 |
58 | /**
59 | * Locates elements whose class name contains the search value; compound class
60 | * names are not permitted.
61 | *
62 | * @param string $class_name
63 | * @return static
64 | */
65 | public static function className($class_name)
66 | {
67 | return new static('class name', $class_name);
68 | }
69 |
70 | /**
71 | * Locates elements matching a CSS selector.
72 | *
73 | * @param string $css_selector
74 | * @return static
75 | */
76 | public static function cssSelector($css_selector)
77 | {
78 | return new static('css selector', $css_selector);
79 | }
80 |
81 | /**
82 | * Locates elements whose ID attribute matches the search value.
83 | *
84 | * @param string $id
85 | * @return static
86 | */
87 | public static function id($id)
88 | {
89 | return new static('id', $id);
90 | }
91 |
92 | /**
93 | * Locates elements whose NAME attribute matches the search value.
94 | *
95 | * @param string $name
96 | * @return static
97 | */
98 | public static function name($name)
99 | {
100 | return new static('name', $name);
101 | }
102 |
103 | /**
104 | * Locates anchor elements whose visible text matches the search value.
105 | *
106 | * @param string $link_text
107 | * @return static
108 | */
109 | public static function linkText($link_text)
110 | {
111 | return new static('link text', $link_text);
112 | }
113 |
114 | /**
115 | * Locates anchor elements whose visible text partially matches the search
116 | * value.
117 | *
118 | * @param string $partial_link_text
119 | * @return static
120 | */
121 | public static function partialLinkText($partial_link_text)
122 | {
123 | return new static('partial link text', $partial_link_text);
124 | }
125 |
126 | /**
127 | * Locates elements whose tag name matches the search value.
128 | *
129 | * @param string $tag_name
130 | * @return static
131 | */
132 | public static function tagName($tag_name)
133 | {
134 | return new static('tag name', $tag_name);
135 | }
136 |
137 | /**
138 | * Locates elements matching an XPath expression.
139 | *
140 | * @param string $xpath
141 | * @return static
142 | */
143 | public static function xpath($xpath)
144 | {
145 | return new static('xpath', $xpath);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/lib/WebDriverCapabilities.php:
--------------------------------------------------------------------------------
1 | type = $element->getAttribute('type');
30 | if ($this->type !== 'checkbox') {
31 | throw new WebDriverException('The input must be of type "checkbox".');
32 | }
33 | }
34 |
35 | public function isMultiple()
36 | {
37 | return true;
38 | }
39 |
40 | public function deselectAll()
41 | {
42 | foreach ($this->getRelatedElements() as $checkbox) {
43 | $this->deselectOption($checkbox);
44 | }
45 | }
46 |
47 | public function deselectByIndex($index)
48 | {
49 | $this->byIndex($index, false);
50 | }
51 |
52 | public function deselectByValue($value)
53 | {
54 | $this->byValue($value, false);
55 | }
56 |
57 | public function deselectByVisibleText($text)
58 | {
59 | $this->byVisibleText($text, false, false);
60 | }
61 |
62 | public function deselectByVisiblePartialText($text)
63 | {
64 | $this->byVisibleText($text, true, false);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/WebDriverCommandExecutor.php:
--------------------------------------------------------------------------------
1 | width = $width;
39 | $this->height = $height;
40 | }
41 |
42 | /**
43 | * Get the height.
44 | *
45 | * @return int The height.
46 | */
47 | public function getHeight()
48 | {
49 | return (int) $this->height;
50 | }
51 |
52 | /**
53 | * Get the width.
54 | *
55 | * @return int The width.
56 | */
57 | public function getWidth()
58 | {
59 | return (int) $this->width;
60 | }
61 |
62 | /**
63 | * Check whether the given dimension is the same as the instance.
64 | *
65 | * @param WebDriverDimension $dimension The dimension to be compared with.
66 | * @return bool Whether the height and the width are the same as the instance.
67 | */
68 | public function equals(self $dimension)
69 | {
70 | return $this->height === $dimension->getHeight() && $this->width === $dimension->getWidth();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/WebDriverDispatcher.php:
--------------------------------------------------------------------------------
1 | driver = $driver;
41 |
42 | return $this;
43 | }
44 |
45 | /**
46 | * @return null|EventFiringWebDriver
47 | */
48 | public function getDefaultDriver()
49 | {
50 | return $this->driver;
51 | }
52 |
53 | /**
54 | * @param WebDriverEventListener $listener
55 | * @return $this
56 | */
57 | public function register(WebDriverEventListener $listener)
58 | {
59 | $this->listeners[] = $listener;
60 |
61 | return $this;
62 | }
63 |
64 | /**
65 | * @param WebDriverEventListener $listener
66 | * @return $this
67 | */
68 | public function unregister(WebDriverEventListener $listener)
69 | {
70 | $key = array_search($listener, $this->listeners, true);
71 | if ($key !== false) {
72 | unset($this->listeners[$key]);
73 | }
74 |
75 | return $this;
76 | }
77 |
78 | /**
79 | * @param mixed $method
80 | * @param mixed $arguments
81 | * @return $this
82 | */
83 | public function dispatch($method, $arguments)
84 | {
85 | foreach ($this->listeners as $listener) {
86 | call_user_func_array([$listener, $method], $arguments);
87 | }
88 |
89 | return $this;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/WebDriverElement.php:
--------------------------------------------------------------------------------
1 | executor = $executor;
28 | }
29 |
30 | public function back()
31 | {
32 | $this->executor->execute(DriverCommand::GO_BACK);
33 |
34 | return $this;
35 | }
36 |
37 | public function forward()
38 | {
39 | $this->executor->execute(DriverCommand::GO_FORWARD);
40 |
41 | return $this;
42 | }
43 |
44 | public function refresh()
45 | {
46 | $this->executor->execute(DriverCommand::REFRESH);
47 |
48 | return $this;
49 | }
50 |
51 | public function to($url)
52 | {
53 | $params = ['url' => (string) $url];
54 | $this->executor->execute(DriverCommand::GET, $params);
55 |
56 | return $this;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/WebDriverNavigationInterface.php:
--------------------------------------------------------------------------------
1 | x = $x;
29 | $this->y = $y;
30 | }
31 |
32 | /**
33 | * Get the x-coordinate.
34 | *
35 | * @return int The x-coordinate of the point.
36 | */
37 | public function getX()
38 | {
39 | return (int) $this->x;
40 | }
41 |
42 | /**
43 | * Get the y-coordinate.
44 | *
45 | * @return int The y-coordinate of the point.
46 | */
47 | public function getY()
48 | {
49 | return (int) $this->y;
50 | }
51 |
52 | /**
53 | * Set the point to a new position.
54 | *
55 | * @param int $new_x
56 | * @param int $new_y
57 | * @return WebDriverPoint The same instance with updated coordinates.
58 | */
59 | public function move($new_x, $new_y)
60 | {
61 | $this->x = $new_x;
62 | $this->y = $new_y;
63 |
64 | return $this;
65 | }
66 |
67 | /**
68 | * Move the current by offsets.
69 | *
70 | * @param int $x_offset
71 | * @param int $y_offset
72 | * @return WebDriverPoint The same instance with updated coordinates.
73 | */
74 | public function moveBy($x_offset, $y_offset)
75 | {
76 | $this->x += $x_offset;
77 | $this->y += $y_offset;
78 |
79 | return $this;
80 | }
81 |
82 | /**
83 | * Check whether the given point is the same as the instance.
84 | *
85 | * @param WebDriverPoint $point The point to be compared with.
86 | * @return bool Whether the x and y coordinates are the same as the instance.
87 | */
88 | public function equals(self $point)
89 | {
90 | return $this->x === $point->getX() &&
91 | $this->y === $point->getY();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lib/WebDriverRadios.php:
--------------------------------------------------------------------------------
1 | type = $element->getAttribute('type');
31 | if ($this->type !== 'radio') {
32 | throw new WebDriverException('The input must be of type "radio".');
33 | }
34 | }
35 |
36 | public function isMultiple()
37 | {
38 | return false;
39 | }
40 |
41 | public function deselectAll()
42 | {
43 | throw new UnsupportedOperationException('You cannot deselect radio buttons');
44 | }
45 |
46 | public function deselectByIndex($index)
47 | {
48 | throw new UnsupportedOperationException('You cannot deselect radio buttons');
49 | }
50 |
51 | public function deselectByValue($value)
52 | {
53 | throw new UnsupportedOperationException('You cannot deselect radio buttons');
54 | }
55 |
56 | public function deselectByVisibleText($text)
57 | {
58 | throw new UnsupportedOperationException('You cannot deselect radio buttons');
59 | }
60 |
61 | public function deselectByVisiblePartialText($text)
62 | {
63 | throw new UnsupportedOperationException('You cannot deselect radio buttons');
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/lib/WebDriverSearchContext.php:
--------------------------------------------------------------------------------
1 | Bar`
63 | *
64 | * @param string $value The value to match against.
65 | *
66 | * @throws NoSuchElementException
67 | */
68 | public function selectByValue($value);
69 |
70 | /**
71 | * Select all options that display text matching the argument. That is, when given "Bar" this would
72 | * select an option like:
73 | *
74 | * ``
75 | *
76 | * @param string $text The visible text to match against.
77 | *
78 | * @throws NoSuchElementException
79 | */
80 | public function selectByVisibleText($text);
81 |
82 | /**
83 | * Select all options that display text partially matching the argument. That is, when given "Bar" this would
84 | * select an option like:
85 | *
86 | * ``
87 | *
88 | * @param string $text The visible text to match against.
89 | *
90 | * @throws NoSuchElementException
91 | */
92 | public function selectByVisiblePartialText($text);
93 |
94 | /**
95 | * Deselect all options in multiple select tag.
96 | *
97 | * @throws UnsupportedOperationException If the SELECT does not support multiple selections
98 | */
99 | public function deselectAll();
100 |
101 | /**
102 | * Deselect the option at the given index.
103 | *
104 | * @param int $index The index of the option. (0-based)
105 | * @throws UnsupportedOperationException If the SELECT does not support multiple selections
106 | */
107 | public function deselectByIndex($index);
108 |
109 | /**
110 | * Deselect all options that have value attribute matching the argument. That is, when given "foo" this would
111 | * deselect an option like:
112 | *
113 | * ``
114 | *
115 | * @param string $value The value to match against.
116 | * @throws UnsupportedOperationException If the SELECT does not support multiple selections
117 | */
118 | public function deselectByValue($value);
119 |
120 | /**
121 | * Deselect all options that display text matching the argument. That is, when given "Bar" this would
122 | * deselect an option like:
123 | *
124 | * ``
125 | *
126 | * @param string $text The visible text to match against.
127 | * @throws UnsupportedOperationException If the SELECT does not support multiple selections
128 | */
129 | public function deselectByVisibleText($text);
130 |
131 | /**
132 | * Deselect all options that display text matching the argument. That is, when given "Bar" this would
133 | * deselect an option like:
134 | *
135 | * ``
136 | *
137 | * @param string $text The visible text to match against.
138 | * @throws UnsupportedOperationException If the SELECT does not support multiple selections
139 | */
140 | public function deselectByVisiblePartialText($text);
141 | }
142 |
--------------------------------------------------------------------------------
/lib/WebDriverTargetLocator.php:
--------------------------------------------------------------------------------
1 | executor = $executor;
38 | $this->isW3cCompliant = $isW3cCompliant;
39 | }
40 |
41 | /**
42 | * Specify the amount of time the driver should wait when searching for an element if it is not immediately present.
43 | *
44 | * @param int $seconds Wait time in second.
45 | * @return WebDriverTimeouts The current instance.
46 | */
47 | public function implicitlyWait($seconds)
48 | {
49 | if ($this->isW3cCompliant) {
50 | $this->executor->execute(
51 | DriverCommand::IMPLICITLY_WAIT,
52 | ['implicit' => $seconds * 1000]
53 | );
54 |
55 | return $this;
56 | }
57 |
58 | $this->executor->execute(
59 | DriverCommand::IMPLICITLY_WAIT,
60 | ['ms' => $seconds * 1000]
61 | );
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * Set the amount of time to wait for an asynchronous script to finish execution before throwing an error.
68 | *
69 | * @param int $seconds Wait time in second.
70 | * @return WebDriverTimeouts The current instance.
71 | */
72 | public function setScriptTimeout($seconds)
73 | {
74 | if ($this->isW3cCompliant) {
75 | $this->executor->execute(
76 | DriverCommand::SET_SCRIPT_TIMEOUT,
77 | ['script' => $seconds * 1000]
78 | );
79 |
80 | return $this;
81 | }
82 |
83 | $this->executor->execute(
84 | DriverCommand::SET_SCRIPT_TIMEOUT,
85 | ['ms' => $seconds * 1000]
86 | );
87 |
88 | return $this;
89 | }
90 |
91 | /**
92 | * Set the amount of time to wait for a page load to complete before throwing an error.
93 | *
94 | * @param int $seconds Wait time in second.
95 | * @return WebDriverTimeouts The current instance.
96 | */
97 | public function pageLoadTimeout($seconds)
98 | {
99 | if ($this->isW3cCompliant) {
100 | $this->executor->execute(
101 | DriverCommand::SET_SCRIPT_TIMEOUT,
102 | ['pageLoad' => $seconds * 1000]
103 | );
104 |
105 | return $this;
106 | }
107 |
108 | $this->executor->execute(DriverCommand::SET_TIMEOUT, [
109 | 'type' => 'page load',
110 | 'ms' => $seconds * 1000,
111 | ]);
112 |
113 | return $this;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/lib/WebDriverUpAction.php:
--------------------------------------------------------------------------------
1 | x = $x;
34 | $this->y = $y;
35 | parent::__construct($touch_screen);
36 | }
37 |
38 | public function perform()
39 | {
40 | $this->touchScreen->up($this->x, $this->y);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/WebDriverWait.php:
--------------------------------------------------------------------------------
1 | driver = $driver;
44 | $this->timeout = isset($timeout_in_second) ? $timeout_in_second : 30;
45 | $this->interval = $interval_in_millisecond ?: 250;
46 | }
47 |
48 | /**
49 | * Calls the function provided with the driver as an argument until the return value is not falsey.
50 | *
51 | * @param callable|WebDriverExpectedCondition $func_or_ec
52 | * @param string $message
53 | *
54 | * @throws NoSuchElementException
55 | * @throws TimeoutException
56 | * @throws \Exception
57 | * @return mixed The return value of $func_or_ec
58 | */
59 | public function until($func_or_ec, $message = '')
60 | {
61 | $end = microtime(true) + $this->timeout;
62 | $last_exception = null;
63 |
64 | while ($end > microtime(true)) {
65 | try {
66 | if ($func_or_ec instanceof WebDriverExpectedCondition) {
67 | $ret_val = call_user_func($func_or_ec->getApply(), $this->driver);
68 | } else {
69 | $ret_val = call_user_func($func_or_ec, $this->driver);
70 | }
71 | if ($ret_val) {
72 | return $ret_val;
73 | }
74 | } catch (NoSuchElementException $e) {
75 | $last_exception = $e;
76 | }
77 | usleep($this->interval * 1000);
78 | }
79 |
80 | if ($last_exception) {
81 | throw $last_exception;
82 | }
83 |
84 | throw new TimeoutException($message);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/logs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/php-webdriver/php-webdriver-archive/066f29231abe283541e199db080f43aba66830b9/logs/.gitkeep
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | ignoreErrors:
3 | - '#Class Symfony\\Component\\Process\\ProcessBuilder not found.#'
4 | - '#Instantiated class Symfony\\Component\\Process\\ProcessBuilder not found.#'
5 | - '#Call to method setPrefix\(\) on an unknown class Symfony\\Component\\Process\\ProcessBuilder#'
6 | # To be fixed:
7 | - '#Call to an undefined method RecursiveIteratorIterator::getSubPathName\(\)#'
8 | - '#Call to an undefined method Facebook\\WebDriver\\WebDriver::getTouch\(\)#'
9 | - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::getCoordinates\(\)#'
10 | - '#Call to an undefined method Facebook\\WebDriver\\WebDriverElement::equals\(\)#'
11 | - '#Unsafe usage of new static\(\)#'
12 |
13 | inferPrivatePropertyTypeFromConstructor: true
14 |
--------------------------------------------------------------------------------