Laravel version update

Laravel version update
This commit is contained in:
Manish Verma
2018-08-06 18:48:58 +05:30
parent d143048413
commit 126fbb0255
13678 changed files with 1031482 additions and 778530 deletions

View File

@@ -0,0 +1,344 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Exception;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxPreferences;
use Facebook\WebDriver\Firefox\FirefoxProfile;
use Facebook\WebDriver\WebDriverCapabilities;
use Facebook\WebDriver\WebDriverPlatform;
class DesiredCapabilities implements WebDriverCapabilities
{
/**
* @var array
*/
private $capabilities;
public function __construct(array $capabilities = [])
{
$this->capabilities = $capabilities;
}
/**
* @return string The name of the browser.
*/
public function getBrowserName()
{
return $this->get(WebDriverCapabilityType::BROWSER_NAME, '');
}
/**
* @param string $browser_name
* @return DesiredCapabilities
*/
public function setBrowserName($browser_name)
{
$this->set(WebDriverCapabilityType::BROWSER_NAME, $browser_name);
return $this;
}
/**
* @return string The version of the browser.
*/
public function getVersion()
{
return $this->get(WebDriverCapabilityType::VERSION, '');
}
/**
* @param string $version
* @return DesiredCapabilities
*/
public function setVersion($version)
{
$this->set(WebDriverCapabilityType::VERSION, $version);
return $this;
}
/**
* @param string $name
* @return mixed The value of a capability.
*/
public function getCapability($name)
{
return $this->get($name);
}
/**
* @param string $name
* @param mixed $value
* @return DesiredCapabilities
*/
public function setCapability($name, $value)
{
$this->set($name, $value);
return $this;
}
/**
* @return string The name of the platform.
*/
public function getPlatform()
{
return $this->get(WebDriverCapabilityType::PLATFORM, '');
}
/**
* @param string $platform
* @return DesiredCapabilities
*/
public function setPlatform($platform)
{
$this->set(WebDriverCapabilityType::PLATFORM, $platform);
return $this;
}
/**
* @param string $capability_name
* @return bool Whether the value is not null and not false.
*/
public function is($capability_name)
{
return (bool) $this->get($capability_name);
}
/**
* @todo Remove in next major release (BC)
* @deprecated All browsers are always JS enabled except HtmlUnit and it's not meaningful to disable JS execution.
* @return bool Whether javascript is enabled.
*/
public function isJavascriptEnabled()
{
return $this->get(WebDriverCapabilityType::JAVASCRIPT_ENABLED, false);
}
/**
* This is a htmlUnit-only option.
*
* @param bool $enabled
* @throws Exception
* @return DesiredCapabilities
* @see https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities
*/
public function setJavascriptEnabled($enabled)
{
$browser = $this->getBrowserName();
if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) {
throw new Exception(
'isJavascriptEnabled() is a htmlunit-only option. ' .
'See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities.'
);
}
$this->set(WebDriverCapabilityType::JAVASCRIPT_ENABLED, $enabled);
return $this;
}
/**
* @return array
*/
public function toArray()
{
if (isset($this->capabilities[ChromeOptions::CAPABILITY]) &&
$this->capabilities[ChromeOptions::CAPABILITY] instanceof ChromeOptions
) {
$this->capabilities[ChromeOptions::CAPABILITY] =
$this->capabilities[ChromeOptions::CAPABILITY]->toArray();
}
if (isset($this->capabilities[FirefoxDriver::PROFILE]) &&
$this->capabilities[FirefoxDriver::PROFILE] instanceof FirefoxProfile
) {
$this->capabilities[FirefoxDriver::PROFILE] =
$this->capabilities[FirefoxDriver::PROFILE]->encode();
}
return $this->capabilities;
}
/**
* @return static
*/
public static function android()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID,
]);
}
/**
* @return static
*/
public static function chrome()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}
/**
* @return static
*/
public static function firefox()
{
$caps = new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
// disable the "Reader View" help tooltip, which can hide elements in the window.document
$profile = new FirefoxProfile();
$profile->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false);
$caps->setCapability(FirefoxDriver::PROFILE, $profile);
return $caps;
}
/**
* @return static
*/
public static function htmlUnit()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}
/**
* @return static
*/
public static function htmlUnitWithJS()
{
$caps = new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
return $caps->setJavascriptEnabled(true);
}
/**
* @return static
*/
public static function internetExplorer()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
]);
}
/**
* @return static
*/
public static function microsoftEdge()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
]);
}
/**
* @return static
*/
public static function iphone()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
]);
}
/**
* @return static
*/
public static function ipad()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
]);
}
/**
* @return static
*/
public static function opera()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}
/**
* @return static
*/
public static function safari()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}
/**
* @return static
*/
public static function phantomjs()
{
return new static([
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
}
/**
* @param string $key
* @param mixed $value
* @return DesiredCapabilities
*/
private function set($key, $value)
{
$this->capabilities[$key] = $value;
return $this;
}
/**
* @param string $key
* @param mixed $default
* @return mixed
*/
private function get($key, $default = null)
{
return isset($this->capabilities[$key])
? $this->capabilities[$key]
: $default;
}
}

View File

@@ -0,0 +1,152 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
/**
* This list of command defined in the WebDriver json wire protocol.
*
* @codeCoverageIgnore
*/
class DriverCommand
{
const GET_ALL_SESSIONS = 'getAllSessions';
const GET_CAPABILITIES = 'getCapabilities';
const NEW_SESSION = 'newSession';
const STATUS = 'status';
const CLOSE = 'close';
const QUIT = 'quit';
const GET = 'get';
const GO_BACK = 'goBack';
const GO_FORWARD = 'goForward';
const REFRESH = 'refresh';
const ADD_COOKIE = 'addCookie';
const GET_ALL_COOKIES = 'getCookies';
const DELETE_COOKIE = 'deleteCookie';
const DELETE_ALL_COOKIES = 'deleteAllCookies';
const FIND_ELEMENT = 'findElement';
const FIND_ELEMENTS = 'findElements';
const FIND_CHILD_ELEMENT = 'findChildElement';
const FIND_CHILD_ELEMENTS = 'findChildElements';
const CLEAR_ELEMENT = 'clearElement';
const CLICK_ELEMENT = 'clickElement';
const SEND_KEYS_TO_ELEMENT = 'sendKeysToElement';
const SEND_KEYS_TO_ACTIVE_ELEMENT = 'sendKeysToActiveElement';
const SUBMIT_ELEMENT = 'submitElement';
const UPLOAD_FILE = 'uploadFile';
const GET_CURRENT_WINDOW_HANDLE = 'getCurrentWindowHandle';
const GET_WINDOW_HANDLES = 'getWindowHandles';
const GET_CURRENT_CONTEXT_HANDLE = 'getCurrentContextHandle';
const GET_CONTEXT_HANDLES = 'getContextHandles';
// Switching between to window/frame/iframe
const SWITCH_TO_WINDOW = 'switchToWindow';
const SWITCH_TO_CONTEXT = 'switchToContext';
const SWITCH_TO_FRAME = 'switchToFrame';
const SWITCH_TO_PARENT_FRAME = 'switchToParentFrame';
const GET_ACTIVE_ELEMENT = 'getActiveElement';
// Information of the page
const GET_CURRENT_URL = 'getCurrentUrl';
const GET_PAGE_SOURCE = 'getPageSource';
const GET_TITLE = 'getTitle';
// Javascript API
const EXECUTE_SCRIPT = 'executeScript';
const EXECUTE_ASYNC_SCRIPT = 'executeAsyncScript';
// API getting information from an element.
const GET_ELEMENT_TEXT = 'getElementText';
const GET_ELEMENT_TAG_NAME = 'getElementTagName';
const IS_ELEMENT_SELECTED = 'isElementSelected';
const IS_ELEMENT_ENABLED = 'isElementEnabled';
const IS_ELEMENT_DISPLAYED = 'isElementDisplayed';
const GET_ELEMENT_LOCATION = 'getElementLocation';
const GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = 'getElementLocationOnceScrolledIntoView';
const GET_ELEMENT_SIZE = 'getElementSize';
const GET_ELEMENT_ATTRIBUTE = 'getElementAttribute';
const GET_ELEMENT_VALUE_OF_CSS_PROPERTY = 'getElementValueOfCssProperty';
const ELEMENT_EQUALS = 'elementEquals';
const SCREENSHOT = 'screenshot';
// Alert API
const ACCEPT_ALERT = 'acceptAlert';
const DISMISS_ALERT = 'dismissAlert';
const GET_ALERT_TEXT = 'getAlertText';
const SET_ALERT_VALUE = 'setAlertValue';
// Timeout API
const SET_TIMEOUT = 'setTimeout';
const IMPLICITLY_WAIT = 'implicitlyWait';
const SET_SCRIPT_TIMEOUT = 'setScriptTimeout';
/** @deprecated */
const EXECUTE_SQL = 'executeSQL';
const GET_LOCATION = 'getLocation';
const SET_LOCATION = 'setLocation';
const GET_APP_CACHE = 'getAppCache';
const GET_APP_CACHE_STATUS = 'getStatus';
const CLEAR_APP_CACHE = 'clearAppCache';
const IS_BROWSER_ONLINE = 'isBrowserOnline';
const SET_BROWSER_ONLINE = 'setBrowserOnline';
// Local storage
const GET_LOCAL_STORAGE_ITEM = 'getLocalStorageItem';
const GET_LOCAL_STORAGE_KEYS = 'getLocalStorageKeys';
const SET_LOCAL_STORAGE_ITEM = 'setLocalStorageItem';
const REMOVE_LOCAL_STORAGE_ITEM = 'removeLocalStorageItem';
const CLEAR_LOCAL_STORAGE = 'clearLocalStorage';
const GET_LOCAL_STORAGE_SIZE = 'getLocalStorageSize';
// Session storage
const GET_SESSION_STORAGE_ITEM = 'getSessionStorageItem';
const GET_SESSION_STORAGE_KEYS = 'getSessionStorageKey';
const SET_SESSION_STORAGE_ITEM = 'setSessionStorageItem';
const REMOVE_SESSION_STORAGE_ITEM = 'removeSessionStorageItem';
const CLEAR_SESSION_STORAGE = 'clearSessionStorage';
const GET_SESSION_STORAGE_SIZE = 'getSessionStorageSize';
// Screen orientation
const SET_SCREEN_ORIENTATION = 'setScreenOrientation';
const GET_SCREEN_ORIENTATION = 'getScreenOrientation';
// These belong to the Advanced user interactions - an element is optional for these commands.
const CLICK = 'mouseClick';
const DOUBLE_CLICK = 'mouseDoubleClick';
const MOUSE_DOWN = 'mouseButtonDown';
const MOUSE_UP = 'mouseButtonUp';
const MOVE_TO = 'mouseMoveTo';
// Those allow interactions with the Input Methods installed on the system.
const IME_GET_AVAILABLE_ENGINES = 'imeGetAvailableEngines';
const IME_GET_ACTIVE_ENGINE = 'imeGetActiveEngine';
const IME_IS_ACTIVATED = 'imeIsActivated';
const IME_DEACTIVATE = 'imeDeactivate';
const IME_ACTIVATE_ENGINE = 'imeActivateEngine';
// These belong to the Advanced Touch API
const TOUCH_SINGLE_TAP = 'touchSingleTap';
const TOUCH_DOWN = 'touchDown';
const TOUCH_UP = 'touchUp';
const TOUCH_MOVE = 'touchMove';
const TOUCH_SCROLL = 'touchScroll';
const TOUCH_DOUBLE_TAP = 'touchDoubleTap';
const TOUCH_LONG_PRESS = 'touchLongPress';
const TOUCH_FLICK = 'touchFlick';
// Window API (beta)
const SET_WINDOW_SIZE = 'setWindowSize';
const SET_WINDOW_POSITION = 'setWindowPosition';
const GET_WINDOW_SIZE = 'getWindowSize';
const GET_WINDOW_POSITION = 'getWindowPosition';
const MAXIMIZE_WINDOW = 'maximizeWindow';
// Logging API
const GET_AVAILABLE_LOG_TYPES = 'getAvailableLogTypes';
const GET_LOG = 'getLog';
const GET_SESSION_LOGS = 'getSessionLogs';
// Mobile API
const GET_NETWORK_CONNECTION = 'getNetworkConnection';
const SET_NETWORK_CONNECTION = 'setNetworkConnection';
private function __construct()
{
}
}

View File

@@ -0,0 +1,26 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
interface ExecuteMethod
{
/**
* @param string $command_name
* @param array $parameters
* @return WebDriverResponse
*/
public function execute($command_name, array $parameters = []);
}

View File

@@ -0,0 +1,29 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
interface FileDetector
{
/**
* Try to detect whether the given $file is a file or not. Return the path
* of the file. Otherwise, return null.
*
* @param string $file
*
* @return null|string The path of the file.
*/
public function getLocalFile($file);
}

View File

@@ -0,0 +1,343 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use BadMethodCallException;
use Facebook\WebDriver\Exception\WebDriverCurlException;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\WebDriverCommandExecutor;
use InvalidArgumentException;
/**
* Command executor talking to the standalone server via HTTP.
*/
class HttpCommandExecutor implements WebDriverCommandExecutor
{
const DEFAULT_HTTP_HEADERS = [
'Content-Type: application/json;charset=UTF-8',
'Accept: application/json',
];
/**
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference
*/
protected static $commands = [
DriverCommand::ACCEPT_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/accept_alert'],
DriverCommand::ADD_COOKIE => ['method' => 'POST', 'url' => '/session/:sessionId/cookie'],
DriverCommand::CLEAR_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'],
DriverCommand::CLICK_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'],
DriverCommand::CLOSE => ['method' => 'DELETE', 'url' => '/session/:sessionId/window'],
DriverCommand::DELETE_ALL_COOKIES => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie'],
DriverCommand::DELETE_COOKIE => ['method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'],
DriverCommand::DISMISS_ALERT => ['method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'],
DriverCommand::ELEMENT_EQUALS => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/equals/:other'],
DriverCommand::FIND_CHILD_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/element'],
DriverCommand::FIND_CHILD_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/elements'],
DriverCommand::EXECUTE_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute'],
DriverCommand::EXECUTE_ASYNC_SCRIPT => ['method' => 'POST', 'url' => '/session/:sessionId/execute_async'],
DriverCommand::FIND_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element'],
DriverCommand::FIND_ELEMENTS => ['method' => 'POST', 'url' => '/session/:sessionId/elements'],
DriverCommand::SWITCH_TO_FRAME => ['method' => 'POST', 'url' => '/session/:sessionId/frame'],
DriverCommand::SWITCH_TO_WINDOW => ['method' => 'POST', 'url' => '/session/:sessionId/window'],
DriverCommand::GET => ['method' => 'POST', 'url' => '/session/:sessionId/url'],
DriverCommand::GET_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/active'],
DriverCommand::GET_ALERT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/alert_text'],
DriverCommand::GET_ALL_COOKIES => ['method' => 'GET', 'url' => '/session/:sessionId/cookie'],
DriverCommand::GET_ALL_SESSIONS => ['method' => 'GET', 'url' => '/sessions'],
DriverCommand::GET_AVAILABLE_LOG_TYPES => ['method' => 'GET', 'url' => '/session/:sessionId/log/types'],
DriverCommand::GET_CURRENT_URL => ['method' => 'GET', 'url' => '/session/:sessionId/url'],
DriverCommand::GET_CURRENT_WINDOW_HANDLE => ['method' => 'GET', 'url' => '/session/:sessionId/window_handle'],
DriverCommand::GET_ELEMENT_ATTRIBUTE => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/attribute/:name',
],
DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/css/:propertyName',
],
DriverCommand::GET_ELEMENT_LOCATION => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/location',
],
DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/location_in_view',
],
DriverCommand::GET_ELEMENT_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'],
DriverCommand::GET_ELEMENT_TAG_NAME => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/name'],
DriverCommand::GET_ELEMENT_TEXT => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'],
DriverCommand::GET_LOG => ['method' => 'POST', 'url' => '/session/:sessionId/log'],
DriverCommand::GET_PAGE_SOURCE => ['method' => 'GET', 'url' => '/session/:sessionId/source'],
DriverCommand::GET_SCREEN_ORIENTATION => ['method' => 'GET', 'url' => '/session/:sessionId/orientation'],
DriverCommand::GET_CAPABILITIES => ['method' => 'GET', 'url' => '/session/:sessionId'],
DriverCommand::GET_TITLE => ['method' => 'GET', 'url' => '/session/:sessionId/title'],
DriverCommand::GET_WINDOW_HANDLES => ['method' => 'GET', 'url' => '/session/:sessionId/window_handles'],
DriverCommand::GET_WINDOW_POSITION => [
'method' => 'GET',
'url' => '/session/:sessionId/window/:windowHandle/position',
],
DriverCommand::GET_WINDOW_SIZE => ['method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/size'],
DriverCommand::GO_BACK => ['method' => 'POST', 'url' => '/session/:sessionId/back'],
DriverCommand::GO_FORWARD => ['method' => 'POST', 'url' => '/session/:sessionId/forward'],
DriverCommand::IS_ELEMENT_DISPLAYED => [
'method' => 'GET',
'url' => '/session/:sessionId/element/:id/displayed',
],
DriverCommand::IS_ELEMENT_ENABLED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/enabled'],
DriverCommand::IS_ELEMENT_SELECTED => ['method' => 'GET', 'url' => '/session/:sessionId/element/:id/selected'],
DriverCommand::MAXIMIZE_WINDOW => [
'method' => 'POST',
'url' => '/session/:sessionId/window/:windowHandle/maximize',
],
DriverCommand::MOUSE_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/buttondown'],
DriverCommand::MOUSE_UP => ['method' => 'POST', 'url' => '/session/:sessionId/buttonup'],
DriverCommand::CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/click'],
DriverCommand::DOUBLE_CLICK => ['method' => 'POST', 'url' => '/session/:sessionId/doubleclick'],
DriverCommand::MOVE_TO => ['method' => 'POST', 'url' => '/session/:sessionId/moveto'],
DriverCommand::NEW_SESSION => ['method' => 'POST', 'url' => '/session'],
DriverCommand::QUIT => ['method' => 'DELETE', 'url' => '/session/:sessionId'],
DriverCommand::REFRESH => ['method' => 'POST', 'url' => '/session/:sessionId/refresh'],
DriverCommand::UPLOAD_FILE => ['method' => 'POST', 'url' => '/session/:sessionId/file'], // undocumented
DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/keys'],
DriverCommand::SET_ALERT_VALUE => ['method' => 'POST', 'url' => '/session/:sessionId/alert_text'],
DriverCommand::SEND_KEYS_TO_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/value'],
DriverCommand::IMPLICITLY_WAIT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/implicit_wait'],
DriverCommand::SET_SCREEN_ORIENTATION => ['method' => 'POST', 'url' => '/session/:sessionId/orientation'],
DriverCommand::SET_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts'],
DriverCommand::SET_SCRIPT_TIMEOUT => ['method' => 'POST', 'url' => '/session/:sessionId/timeouts/async_script'],
DriverCommand::SET_WINDOW_POSITION => [
'method' => 'POST',
'url' => '/session/:sessionId/window/:windowHandle/position',
],
DriverCommand::SET_WINDOW_SIZE => [
'method' => 'POST',
'url' => '/session/:sessionId/window/:windowHandle/size',
],
DriverCommand::SUBMIT_ELEMENT => ['method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'],
DriverCommand::SCREENSHOT => ['method' => 'GET', 'url' => '/session/:sessionId/screenshot'],
DriverCommand::TOUCH_SINGLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/click'],
DriverCommand::TOUCH_DOWN => ['method' => 'POST', 'url' => '/session/:sessionId/touch/down'],
DriverCommand::TOUCH_DOUBLE_TAP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'],
DriverCommand::TOUCH_FLICK => ['method' => 'POST', 'url' => '/session/:sessionId/touch/flick'],
DriverCommand::TOUCH_LONG_PRESS => ['method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'],
DriverCommand::TOUCH_MOVE => ['method' => 'POST', 'url' => '/session/:sessionId/touch/move'],
DriverCommand::TOUCH_SCROLL => ['method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'],
DriverCommand::TOUCH_UP => ['method' => 'POST', 'url' => '/session/:sessionId/touch/up'],
];
/**
* @var string
*/
protected $url;
/**
* @var resource
*/
protected $curl;
/**
* @param string $url
* @param string|null $http_proxy
* @param int|null $http_proxy_port
*/
public function __construct($url, $http_proxy = null, $http_proxy_port = null)
{
$this->url = $url;
$this->curl = curl_init();
if (!empty($http_proxy)) {
curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy);
if ($http_proxy_port !== null) {
curl_setopt($this->curl, CURLOPT_PROXYPORT, $http_proxy_port);
}
}
// Get credentials from $url (if any)
$matches = null;
if (preg_match("/^(https?:\/\/)(.*):(.*)@(.*?)/U", $url, $matches)) {
$this->url = $matches[1] . $matches[4];
$auth_creds = $matches[2] . ':' . $matches[3];
curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($this->curl, CURLOPT_USERPWD, $auth_creds);
}
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS);
$this->setRequestTimeout(30000);
$this->setConnectionTimeout(30000);
}
/**
* Set timeout for the connect phase
*
* @param int $timeout_in_ms Timeout in milliseconds
* @return HttpCommandExecutor
*/
public function setConnectionTimeout($timeout_in_ms)
{
// There is a PHP bug in some versions which didn't define the constant.
curl_setopt(
$this->curl,
/* CURLOPT_CONNECTTIMEOUT_MS */
156,
$timeout_in_ms
);
return $this;
}
/**
* Set the maximum time of a request
*
* @param int $timeout_in_ms Timeout in milliseconds
* @return HttpCommandExecutor
*/
public function setRequestTimeout($timeout_in_ms)
{
// There is a PHP bug in some versions (at least for PHP 5.3.3) which
// didn't define the constant.
curl_setopt(
$this->curl,
/* CURLOPT_TIMEOUT_MS */
155,
$timeout_in_ms
);
return $this;
}
/**
* @param WebDriverCommand $command
*
* @throws WebDriverException
* @return WebDriverResponse
*/
public function execute(WebDriverCommand $command)
{
if (!isset(self::$commands[$command->getName()])) {
throw new InvalidArgumentException($command->getName() . ' is not a valid command.');
}
$raw = self::$commands[$command->getName()];
$http_method = $raw['method'];
$url = $raw['url'];
$url = str_replace(':sessionId', $command->getSessionID(), $url);
$params = $command->getParameters();
foreach ($params as $name => $value) {
if ($name[0] === ':') {
$url = str_replace($name, $value, $url);
unset($params[$name]);
}
}
if ($params && is_array($params) && $http_method !== 'POST') {
throw new BadMethodCallException(sprintf(
'The http method called for %s is %s but it has to be POST' .
' if you want to pass the JSON params %s',
$url,
$http_method,
json_encode($params)
));
}
curl_setopt($this->curl, CURLOPT_URL, $this->url . $url);
// https://github.com/facebook/php-webdriver/issues/173
if ($command->getName() === DriverCommand::NEW_SESSION) {
curl_setopt($this->curl, CURLOPT_POST, 1);
} else {
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $http_method);
}
if (in_array($http_method, ['POST', 'PUT'])) {
// Disable sending 'Expect: 100-Continue' header, as it is causing issues with eg. squid proxy
// https://tools.ietf.org/html/rfc7231#section-5.1.1
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array_merge(static::DEFAULT_HTTP_HEADERS, ['Expect:']));
} else {
curl_setopt($this->curl, CURLOPT_HTTPHEADER, static::DEFAULT_HTTP_HEADERS);
}
$encoded_params = null;
if ($http_method === 'POST' && $params && is_array($params)) {
$encoded_params = json_encode($params);
}
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $encoded_params);
$raw_results = trim(curl_exec($this->curl));
if ($error = curl_error($this->curl)) {
$msg = sprintf(
'Curl error thrown for http %s to %s',
$http_method,
$url
);
if ($params && is_array($params)) {
$msg .= sprintf(' with params: %s', json_encode($params));
}
throw new WebDriverCurlException($msg . "\n\n" . $error);
}
$results = json_decode($raw_results, true);
if ($results === null && json_last_error() !== JSON_ERROR_NONE) {
throw new WebDriverException(
sprintf(
"JSON decoding of remote response failed.\n" .
"Error code: %d\n" .
"The response: '%s'\n",
json_last_error(),
$raw_results
)
);
}
$value = null;
if (is_array($results) && array_key_exists('value', $results)) {
$value = $results['value'];
}
$message = null;
if (is_array($value) && array_key_exists('message', $value)) {
$message = $value['message'];
}
$sessionId = null;
if (is_array($results) && array_key_exists('sessionId', $results)) {
$sessionId = $results['sessionId'];
}
$status = isset($results['status']) ? $results['status'] : 0;
if ($status != 0) {
WebDriverException::throwException($status, $message, $results);
}
$response = new WebDriverResponse($sessionId);
return $response
->setStatus($status)
->setValue($value);
}
/**
* @return string
*/
public function getAddressOfRemoteServer()
{
return $this->url;
}
}

View File

@@ -0,0 +1,33 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
class LocalFileDetector implements FileDetector
{
/**
* @param string $file
*
* @return null|string
*/
public function getLocalFile($file)
{
if (is_file($file)) {
return $file;
}
return null;
}
}

View File

@@ -0,0 +1,42 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
class RemoteExecuteMethod implements ExecuteMethod
{
/**
* @var RemoteWebDriver
*/
private $driver;
/**
* @param RemoteWebDriver $driver
*/
public function __construct(RemoteWebDriver $driver)
{
$this->driver = $driver;
}
/**
* @param string $command_name
* @param array $parameters
* @return mixed
*/
public function execute($command_name, array $parameters = [])
{
return $this->driver->execute($command_name, $parameters);
}
}

View File

@@ -0,0 +1,84 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\WebDriverKeys;
/**
* Execute keyboard commands for RemoteWebDriver.
*/
class RemoteKeyboard implements WebDriverKeyboard
{
/**
* @var RemoteExecuteMethod
*/
private $executor;
/**
* @param RemoteExecuteMethod $executor
*/
public function __construct(RemoteExecuteMethod $executor)
{
$this->executor = $executor;
}
/**
* Send keys to active element
* @param string|array $keys
* @return $this
*/
public function sendKeys($keys)
{
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
'value' => WebDriverKeys::encode($keys),
]);
return $this;
}
/**
* Press a modifier key
*
* @see WebDriverKeys
* @param string $key
* @return $this
*/
public function pressKey($key)
{
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
'value' => [(string) $key],
]);
return $this;
}
/**
* Release a modifier key
*
* @see WebDriverKeys
* @param string $key
* @return $this
*/
public function releaseKey($key)
{
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, [
'value' => [(string) $key],
]);
return $this;
}
}

View File

@@ -0,0 +1,144 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\WebDriverMouse;
/**
* Execute mouse commands for RemoteWebDriver.
*/
class RemoteMouse implements WebDriverMouse
{
/**
* @var RemoteExecuteMethod
*/
private $executor;
/**
* @param RemoteExecuteMethod $executor
*/
public function __construct(RemoteExecuteMethod $executor)
{
$this->executor = $executor;
}
/**
* @param null|WebDriverCoordinates $where
*
* @return RemoteMouse
*/
public function click(WebDriverCoordinates $where = null)
{
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::CLICK, [
'button' => 0,
]);
return $this;
}
/**
* @param WebDriverCoordinates $where
*
* @return RemoteMouse
*/
public function contextClick(WebDriverCoordinates $where = null)
{
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::CLICK, [
'button' => 2,
]);
return $this;
}
/**
* @param WebDriverCoordinates $where
*
* @return RemoteMouse
*/
public function doubleClick(WebDriverCoordinates $where = null)
{
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::DOUBLE_CLICK);
return $this;
}
/**
* @param WebDriverCoordinates $where
*
* @return RemoteMouse
*/
public function mouseDown(WebDriverCoordinates $where = null)
{
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::MOUSE_DOWN);
return $this;
}
/**
* @param WebDriverCoordinates $where
* @param int|null $x_offset
* @param int|null $y_offset
*
* @return RemoteMouse
*/
public function mouseMove(
WebDriverCoordinates $where = null,
$x_offset = null,
$y_offset = null
) {
$params = [];
if ($where !== null) {
$params['element'] = $where->getAuxiliary();
}
if ($x_offset !== null) {
$params['xoffset'] = $x_offset;
}
if ($y_offset !== null) {
$params['yoffset'] = $y_offset;
}
$this->executor->execute(DriverCommand::MOVE_TO, $params);
return $this;
}
/**
* @param WebDriverCoordinates $where
*
* @return RemoteMouse
*/
public function mouseUp(WebDriverCoordinates $where = null)
{
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::MOUSE_UP);
return $this;
}
/**
* @param WebDriverCoordinates $where
*/
protected function moveIfNeeded(WebDriverCoordinates $where = null)
{
if ($where) {
$this->mouseMove($where);
}
}
}

View File

@@ -0,0 +1,117 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverAlert;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverTargetLocator;
/**
* Used to locate a given frame or window for RemoteWebDriver.
*/
class RemoteTargetLocator implements WebDriverTargetLocator
{
/**
* @var ExecuteMethod
*/
protected $executor;
/**
* @var WebDriver
*/
protected $driver;
public function __construct($executor, $driver)
{
$this->executor = $executor;
$this->driver = $driver;
}
/**
* Switch to the main document if the page contains iframes. Otherwise, switch
* to the first frame on the page.
*
* @return WebDriver The driver focused on the top window or the first frame.
*/
public function defaultContent()
{
$params = ['id' => null];
$this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);
return $this->driver;
}
/**
* Switch to the iframe by its id or name.
*
* @param WebDriverElement|string $frame The WebDriverElement,
* the id or the name of the frame.
* @return WebDriver The driver focused on the given frame.
*/
public function frame($frame)
{
if ($frame instanceof WebDriverElement) {
$id = ['ELEMENT' => $frame->getID()];
} else {
$id = (string) $frame;
}
$params = ['id' => $id];
$this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);
return $this->driver;
}
/**
* Switch the focus to another window by its handle.
*
* @param string $handle The handle of the window to be focused on.
* @return WebDriver The driver focused on the given window.
* @see WebDriver::getWindowHandles
*/
public function window($handle)
{
$params = ['name' => (string) $handle];
$this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params);
return $this->driver;
}
/**
* Switch to the currently active modal dialog for this particular driver
* instance.
*
* @return WebDriverAlert
*/
public function alert()
{
return new WebDriverAlert($this->executor);
}
/**
* Switches to the element that currently has focus within the document
* currently "switched to", or the body element if this cannot be detected.
*
* @return RemoteWebElement
*/
public function activeElement()
{
$response = $this->driver->execute(DriverCommand::GET_ACTIVE_ELEMENT, []);
$method = new RemoteExecuteMethod($this->driver);
return new RemoteWebElement($method, $response['ELEMENT']);
}
}

View File

@@ -0,0 +1,201 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen;
use Facebook\WebDriver\WebDriverElement;
/**
* Execute touch commands for RemoteWebDriver.
*/
class RemoteTouchScreen implements WebDriverTouchScreen
{
/**
* @var RemoteExecuteMethod
*/
private $executor;
/**
* @param RemoteExecuteMethod $executor
*/
public function __construct(RemoteExecuteMethod $executor)
{
$this->executor = $executor;
}
/**
* @param WebDriverElement $element
*
* @return RemoteTouchScreen The instance.
*/
public function tap(WebDriverElement $element)
{
$this->executor->execute(
DriverCommand::TOUCH_SINGLE_TAP,
['element' => $element->getID()]
);
return $this;
}
/**
* @param WebDriverElement $element
*
* @return RemoteTouchScreen The instance.
*/
public function doubleTap(WebDriverElement $element)
{
$this->executor->execute(
DriverCommand::TOUCH_DOUBLE_TAP,
['element' => $element->getID()]
);
return $this;
}
/**
* @param int $x
* @param int $y
*
* @return RemoteTouchScreen The instance.
*/
public function down($x, $y)
{
$this->executor->execute(DriverCommand::TOUCH_DOWN, [
'x' => $x,
'y' => $y,
]);
return $this;
}
/**
* @param int $xspeed
* @param int $yspeed
*
* @return RemoteTouchScreen The instance.
*/
public function flick($xspeed, $yspeed)
{
$this->executor->execute(DriverCommand::TOUCH_FLICK, [
'xspeed' => $xspeed,
'yspeed' => $yspeed,
]);
return $this;
}
/**
* @param WebDriverElement $element
* @param int $xoffset
* @param int $yoffset
* @param int $speed
*
* @return RemoteTouchScreen The instance.
*/
public function flickFromElement(WebDriverElement $element, $xoffset, $yoffset, $speed)
{
$this->executor->execute(DriverCommand::TOUCH_FLICK, [
'xoffset' => $xoffset,
'yoffset' => $yoffset,
'element' => $element->getID(),
'speed' => $speed,
]);
return $this;
}
/**
* @param WebDriverElement $element
*
* @return RemoteTouchScreen The instance.
*/
public function longPress(WebDriverElement $element)
{
$this->executor->execute(
DriverCommand::TOUCH_LONG_PRESS,
['element' => $element->getID()]
);
return $this;
}
/**
* @param int $x
* @param int $y
*
* @return RemoteTouchScreen The instance.
*/
public function move($x, $y)
{
$this->executor->execute(DriverCommand::TOUCH_MOVE, [
'x' => $x,
'y' => $y,
]);
return $this;
}
/**
* @param int $xoffset
* @param int $yoffset
*
* @return RemoteTouchScreen The instance.
*/
public function scroll($xoffset, $yoffset)
{
$this->executor->execute(DriverCommand::TOUCH_SCROLL, [
'xoffset' => $xoffset,
'yoffset' => $yoffset,
]);
return $this;
}
/**
* @param WebDriverElement $element
* @param int $xoffset
* @param int $yoffset
*
* @return RemoteTouchScreen The instance.
*/
public function scrollFromElement(WebDriverElement $element, $xoffset, $yoffset)
{
$this->executor->execute(DriverCommand::TOUCH_SCROLL, [
'element' => $element->getID(),
'xoffset' => $xoffset,
'yoffset' => $yoffset,
]);
return $this;
}
/**
* @param int $x
* @param int $y
*
* @return RemoteTouchScreen The instance.
*/
public function up($x, $y)
{
$this->executor->execute(DriverCommand::TOUCH_UP, [
'x' => $x,
'y' => $y,
]);
return $this;
}
}

View File

@@ -0,0 +1,620 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\Interactions\WebDriverActions;
use Facebook\WebDriver\JavaScriptExecutor;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverCapabilities;
use Facebook\WebDriver\WebDriverCommandExecutor;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverHasInputDevices;
use Facebook\WebDriver\WebDriverNavigation;
use Facebook\WebDriver\WebDriverOptions;
use Facebook\WebDriver\WebDriverWait;
class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInputDevices
{
/**
* @var HttpCommandExecutor|null
*/
protected $executor;
/**
* @var WebDriverCapabilities
*/
protected $capabilities;
/**
* @var string
*/
protected $sessionID;
/**
* @var RemoteMouse
*/
protected $mouse;
/**
* @var RemoteKeyboard
*/
protected $keyboard;
/**
* @var RemoteTouchScreen
*/
protected $touch;
/**
* @var RemoteExecuteMethod
*/
protected $executeMethod;
/**
* @param HttpCommandExecutor $commandExecutor
* @param string $sessionId
* @param WebDriverCapabilities|null $capabilities
*/
protected function __construct(
HttpCommandExecutor $commandExecutor,
$sessionId,
WebDriverCapabilities $capabilities = null
) {
$this->executor = $commandExecutor;
$this->sessionID = $sessionId;
if ($capabilities !== null) {
$this->capabilities = $capabilities;
}
}
/**
* Construct the RemoteWebDriver by a desired capabilities.
*
* @param string $selenium_server_url The url of the remote Selenium WebDriver server
* @param DesiredCapabilities|array $desired_capabilities The desired capabilities
* @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server
* @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server
* @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through
* @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through
* @param DesiredCapabilities $required_capabilities The required capabilities
* @return static
*/
public static function create(
$selenium_server_url = 'http://localhost:4444/wd/hub',
$desired_capabilities = null,
$connection_timeout_in_ms = null,
$request_timeout_in_ms = null,
$http_proxy = null,
$http_proxy_port = null,
DesiredCapabilities $required_capabilities = null
) {
$selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url);
$desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities);
$executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port);
if ($connection_timeout_in_ms !== null) {
$executor->setConnectionTimeout($connection_timeout_in_ms);
}
if ($request_timeout_in_ms !== null) {
$executor->setRequestTimeout($request_timeout_in_ms);
}
if ($required_capabilities !== null) {
// TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities.
// This will probably change in future with the W3C WebDriver spec, but is the only way how to pass these
// values now.
$desired_capabilities->setCapability('requiredCapabilities', $required_capabilities->toArray());
}
$command = new WebDriverCommand(
null,
DriverCommand::NEW_SESSION,
['desiredCapabilities' => $desired_capabilities->toArray()]
);
$response = $executor->execute($command);
$returnedCapabilities = new DesiredCapabilities($response->getValue());
$driver = new static($executor, $response->getSessionID(), $returnedCapabilities);
return $driver;
}
/**
* [Experimental] Construct the RemoteWebDriver by an existing session.
*
* This constructor can boost the performance a lot by reusing the same browser for the whole test suite.
* You cannot pass the desired capabilities because the session was created before.
*
* @param string $selenium_server_url The url of the remote Selenium WebDriver server
* @param string $session_id The existing session id
* @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server
* @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server
* @return static
*/
public static function createBySessionID(
$session_id,
$selenium_server_url = 'http://localhost:4444/wd/hub',
$connection_timeout_in_ms = null,
$request_timeout_in_ms = null
) {
$executor = new HttpCommandExecutor($selenium_server_url);
if ($connection_timeout_in_ms !== null) {
$executor->setConnectionTimeout($connection_timeout_in_ms);
}
if ($request_timeout_in_ms !== null) {
$executor->setRequestTimeout($request_timeout_in_ms);
}
return new static($executor, $session_id);
}
/**
* Close the current window.
*
* @return RemoteWebDriver The current instance.
*/
public function close()
{
$this->execute(DriverCommand::CLOSE, []);
return $this;
}
/**
* Find the first WebDriverElement using the given mechanism.
*
* @param WebDriverBy $by
* @return RemoteWebElement NoSuchElementException is thrown in HttpCommandExecutor if no element is found.
* @see WebDriverBy
*/
public function findElement(WebDriverBy $by)
{
$params = ['using' => $by->getMechanism(), 'value' => $by->getValue()];
$raw_element = $this->execute(
DriverCommand::FIND_ELEMENT,
$params
);
return $this->newElement($raw_element['ELEMENT']);
}
/**
* Find all WebDriverElements within the current page using the given mechanism.
*
* @param WebDriverBy $by
* @return RemoteWebElement[] A list of all WebDriverElements, or an empty array if nothing matches
* @see WebDriverBy
*/
public function findElements(WebDriverBy $by)
{
$params = ['using' => $by->getMechanism(), 'value' => $by->getValue()];
$raw_elements = $this->execute(
DriverCommand::FIND_ELEMENTS,
$params
);
$elements = [];
foreach ($raw_elements as $raw_element) {
$elements[] = $this->newElement($raw_element['ELEMENT']);
}
return $elements;
}
/**
* Load a new web page in the current browser window.
*
* @param string $url
*
* @return RemoteWebDriver The current instance.
*/
public function get($url)
{
$params = ['url' => (string) $url];
$this->execute(DriverCommand::GET, $params);
return $this;
}
/**
* Get a string representing the current URL that the browser is looking at.
*
* @return string The current URL.
*/
public function getCurrentURL()
{
return $this->execute(DriverCommand::GET_CURRENT_URL);
}
/**
* Get the source of the last loaded page.
*
* @return string The current page source.
*/
public function getPageSource()
{
return $this->execute(DriverCommand::GET_PAGE_SOURCE);
}
/**
* Get the title of the current page.
*
* @return string The title of the current page.
*/
public function getTitle()
{
return $this->execute(DriverCommand::GET_TITLE);
}
/**
* Return an opaque handle to this window that uniquely identifies it within this driver instance.
*
* @return string The current window handle.
*/
public function getWindowHandle()
{
return $this->execute(
DriverCommand::GET_CURRENT_WINDOW_HANDLE,
[]
);
}
/**
* Get all window handles available to the current session.
*
* @return array An array of string containing all available window handles.
*/
public function getWindowHandles()
{
return $this->execute(DriverCommand::GET_WINDOW_HANDLES, []);
}
/**
* Quits this driver, closing every associated window.
*/
public function quit()
{
$this->execute(DriverCommand::QUIT);
$this->executor = null;
}
/**
* Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.
* The executed script is assumed to be synchronous and the result of evaluating the script will be returned.
*
* @param string $script The script to inject.
* @param array $arguments The arguments of the script.
* @return mixed The return value of the script.
*/
public function executeScript($script, array $arguments = [])
{
$params = [
'script' => $script,
'args' => $this->prepareScriptArguments($arguments),
];
return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params);
}
/**
* Inject a snippet of JavaScript into the page for asynchronous execution in the context of the currently selected
* frame.
*
* The driver will pass a callback as the last argument to the snippet, and block until the callback is invoked.
*
* You may need to define script timeout using `setScriptTimeout()` method of `WebDriverTimeouts` first.
*
* @param string $script The script to inject.
* @param array $arguments The arguments of the script.
* @return mixed The value passed by the script to the callback.
*/
public function executeAsyncScript($script, array $arguments = [])
{
$params = [
'script' => $script,
'args' => $this->prepareScriptArguments($arguments),
];
return $this->execute(
DriverCommand::EXECUTE_ASYNC_SCRIPT,
$params
);
}
/**
* Take a screenshot of the current page.
*
* @param string $save_as The path of the screenshot to be saved.
* @return string The screenshot in PNG format.
*/
public function takeScreenshot($save_as = null)
{
$screenshot = base64_decode(
$this->execute(DriverCommand::SCREENSHOT)
);
if ($save_as) {
file_put_contents($save_as, $screenshot);
}
return $screenshot;
}
/**
* Construct a new WebDriverWait by the current WebDriver instance.
* Sample usage:
*
* ```
* $driver->wait(20, 1000)->until(
* WebDriverExpectedCondition::titleIs('WebDriver Page')
* );
* ```
* @param int $timeout_in_second
* @param int $interval_in_millisecond
*
* @return WebDriverWait
*/
public function wait($timeout_in_second = 30, $interval_in_millisecond = 250)
{
return new WebDriverWait(
$this,
$timeout_in_second,
$interval_in_millisecond
);
}
/**
* An abstraction for managing stuff you would do in a browser menu. For example, adding and deleting cookies.
*
* @return WebDriverOptions
*/
public function manage()
{
return new WebDriverOptions($this->getExecuteMethod());
}
/**
* An abstraction allowing the driver to access the browser's history and to navigate to a given URL.
*
* @return WebDriverNavigation
* @see WebDriverNavigation
*/
public function navigate()
{
return new WebDriverNavigation($this->getExecuteMethod());
}
/**
* Switch to a different window or frame.
*
* @return RemoteTargetLocator
* @see RemoteTargetLocator
*/
public function switchTo()
{
return new RemoteTargetLocator($this->getExecuteMethod(), $this);
}
/**
* @return RemoteMouse
*/
public function getMouse()
{
if (!$this->mouse) {
$this->mouse = new RemoteMouse($this->getExecuteMethod());
}
return $this->mouse;
}
/**
* @return RemoteKeyboard
*/
public function getKeyboard()
{
if (!$this->keyboard) {
$this->keyboard = new RemoteKeyboard($this->getExecuteMethod());
}
return $this->keyboard;
}
/**
* @return RemoteTouchScreen
*/
public function getTouch()
{
if (!$this->touch) {
$this->touch = new RemoteTouchScreen($this->getExecuteMethod());
}
return $this->touch;
}
/**
* Construct a new action builder.
*
* @return WebDriverActions
*/
public function action()
{
return new WebDriverActions($this);
}
/**
* Set the command executor of this RemoteWebdriver
*
* @deprecated To be removed in the future. Executor should be passed in the constructor.
* @internal
* @codeCoverageIgnore
* @param WebDriverCommandExecutor $executor Despite the typehint, it have be an instance of HttpCommandExecutor.
* @return RemoteWebDriver
*/
public function setCommandExecutor(WebDriverCommandExecutor $executor)
{
$this->executor = $executor;
return $this;
}
/**
* Get the command executor of this RemoteWebdriver
*
* @return HttpCommandExecutor
*/
public function getCommandExecutor()
{
return $this->executor;
}
/**
* Set the session id of the RemoteWebDriver.
*
* @deprecated To be removed in the future. Session ID should be passed in the constructor.
* @internal
* @codeCoverageIgnore
* @param string $session_id
* @return RemoteWebDriver
*/
public function setSessionID($session_id)
{
$this->sessionID = $session_id;
return $this;
}
/**
* Get current selenium sessionID
*
* @return string
*/
public function getSessionID()
{
return $this->sessionID;
}
/**
* Get capabilities of the RemoteWebDriver.
*
* @return WebDriverCapabilities
*/
public function getCapabilities()
{
return $this->capabilities;
}
/**
* Returns a list of the currently active sessions.
*
* @param string $selenium_server_url The url of the remote Selenium WebDriver server
* @param int $timeout_in_ms
* @return array
*/
public static function getAllSessions($selenium_server_url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000)
{
$executor = new HttpCommandExecutor($selenium_server_url);
$executor->setConnectionTimeout($timeout_in_ms);
$command = new WebDriverCommand(
null,
DriverCommand::GET_ALL_SESSIONS,
[]
);
return $executor->execute($command)->getValue();
}
public function execute($command_name, $params = [])
{
$command = new WebDriverCommand(
$this->sessionID,
$command_name,
$params
);
if ($this->executor) {
$response = $this->executor->execute($command);
return $response->getValue();
}
return null;
}
/**
* Prepare arguments for JavaScript injection
*
* @param array $arguments
* @return array
*/
protected function prepareScriptArguments(array $arguments)
{
$args = [];
foreach ($arguments as $key => $value) {
if ($value instanceof WebDriverElement) {
$args[$key] = ['ELEMENT' => $value->getID()];
} else {
if (is_array($value)) {
$value = $this->prepareScriptArguments($value);
}
$args[$key] = $value;
}
}
return $args;
}
/**
* @return RemoteExecuteMethod
*/
protected function getExecuteMethod()
{
if (!$this->executeMethod) {
$this->executeMethod = new RemoteExecuteMethod($this);
}
return $this->executeMethod;
}
/**
* Return the WebDriverElement with the given id.
*
* @param string $id The id of the element to be created.
* @return RemoteWebElement
*/
protected function newElement($id)
{
return new RemoteWebElement($this->getExecuteMethod(), $id);
}
/**
* Cast legacy types (array or null) to DesiredCapabilities object. To be removed in future when instance of
* DesiredCapabilities will be required.
*
* @param array|DesiredCapabilities|null $desired_capabilities
* @return DesiredCapabilities
*/
protected static function castToDesiredCapabilitiesObject($desired_capabilities = null)
{
if ($desired_capabilities === null) {
return new DesiredCapabilities();
}
if (is_array($desired_capabilities)) {
return new DesiredCapabilities($desired_capabilities);
}
return $desired_capabilities;
}
}

View File

@@ -0,0 +1,453 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverDimension;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverKeys;
use Facebook\WebDriver\WebDriverPoint;
use ZipArchive;
/**
* Represents an HTML element.
*/
class RemoteWebElement implements WebDriverElement, WebDriverLocatable
{
/**
* @var RemoteExecuteMethod
*/
protected $executor;
/**
* @var string
*/
protected $id;
/**
* @var UselessFileDetector
*/
protected $fileDetector;
/**
* @param RemoteExecuteMethod $executor
* @param string $id
*/
public function __construct(RemoteExecuteMethod $executor, $id)
{
$this->executor = $executor;
$this->id = $id;
$this->fileDetector = new UselessFileDetector();
}
/**
* If this element is a TEXTAREA or text INPUT element, this will clear the value.
*
* @return RemoteWebElement The current instance.
*/
public function clear()
{
$this->executor->execute(
DriverCommand::CLEAR_ELEMENT,
[':id' => $this->id]
);
return $this;
}
/**
* Click this element.
*
* @return RemoteWebElement The current instance.
*/
public function click()
{
$this->executor->execute(
DriverCommand::CLICK_ELEMENT,
[':id' => $this->id]
);
return $this;
}
/**
* Find the first WebDriverElement within this element using the given mechanism.
*
* @param WebDriverBy $by
* @return RemoteWebElement NoSuchElementException is thrown in
* HttpCommandExecutor if no element is found.
* @see WebDriverBy
*/
public function findElement(WebDriverBy $by)
{
$params = [
'using' => $by->getMechanism(),
'value' => $by->getValue(),
':id' => $this->id,
];
$raw_element = $this->executor->execute(
DriverCommand::FIND_CHILD_ELEMENT,
$params
);
return $this->newElement($raw_element['ELEMENT']);
}
/**
* Find all WebDriverElements within this element using the given mechanism.
*
* @param WebDriverBy $by
* @return RemoteWebElement[] A list of all WebDriverElements, or an empty
* array if nothing matches
* @see WebDriverBy
*/
public function findElements(WebDriverBy $by)
{
$params = [
'using' => $by->getMechanism(),
'value' => $by->getValue(),
':id' => $this->id,
];
$raw_elements = $this->executor->execute(
DriverCommand::FIND_CHILD_ELEMENTS,
$params
);
$elements = [];
foreach ($raw_elements as $raw_element) {
$elements[] = $this->newElement($raw_element['ELEMENT']);
}
return $elements;
}
/**
* Get the value of a the given attribute of the element.
*
* @param string $attribute_name The name of the attribute.
* @return string|null The value of the attribute.
*/
public function getAttribute($attribute_name)
{
$params = [
':name' => $attribute_name,
':id' => $this->id,
];
return $this->executor->execute(
DriverCommand::GET_ELEMENT_ATTRIBUTE,
$params
);
}
/**
* Get the value of a given CSS property.
*
* @param string $css_property_name The name of the CSS property.
* @return string The value of the CSS property.
*/
public function getCSSValue($css_property_name)
{
$params = [
':propertyName' => $css_property_name,
':id' => $this->id,
];
return $this->executor->execute(
DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
$params
);
}
/**
* Get the location of element relative to the top-left corner of the page.
*
* @return WebDriverPoint The location of the element.
*/
public function getLocation()
{
$location = $this->executor->execute(
DriverCommand::GET_ELEMENT_LOCATION,
[':id' => $this->id]
);
return new WebDriverPoint($location['x'], $location['y']);
}
/**
* Try scrolling the element into the view port and return the location of
* element relative to the top-left corner of the page afterwards.
*
* @return WebDriverPoint The location of the element.
*/
public function getLocationOnScreenOnceScrolledIntoView()
{
$location = $this->executor->execute(
DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW,
[':id' => $this->id]
);
return new WebDriverPoint($location['x'], $location['y']);
}
/**
* @return WebDriverCoordinates
*/
public function getCoordinates()
{
$element = $this;
$on_screen = null; // planned but not yet implemented
$in_view_port = function () use ($element) {
return $element->getLocationOnScreenOnceScrolledIntoView();
};
$on_page = function () use ($element) {
return $element->getLocation();
};
$auxiliary = $this->getID();
return new WebDriverCoordinates(
$on_screen,
$in_view_port,
$on_page,
$auxiliary
);
}
/**
* Get the size of element.
*
* @return WebDriverDimension The dimension of the element.
*/
public function getSize()
{
$size = $this->executor->execute(
DriverCommand::GET_ELEMENT_SIZE,
[':id' => $this->id]
);
return new WebDriverDimension($size['width'], $size['height']);
}
/**
* Get the (lowercase) tag name of this element.
*
* @return string The tag name.
*/
public function getTagName()
{
// Force tag name to be lowercase as expected by JsonWire protocol for Opera driver
// until this issue is not resolved :
// https://github.com/operasoftware/operadriver/issues/102
// Remove it when fixed to be consistent with the protocol.
return mb_strtolower($this->executor->execute(
DriverCommand::GET_ELEMENT_TAG_NAME,
[':id' => $this->id]
));
}
/**
* Get the visible (i.e. not hidden by CSS) innerText of this element,
* including sub-elements, without any leading or trailing whitespace.
*
* @return string The visible innerText of this element.
*/
public function getText()
{
return $this->executor->execute(
DriverCommand::GET_ELEMENT_TEXT,
[':id' => $this->id]
);
}
/**
* Is this element displayed or not? This method avoids the problem of having
* to parse an element's "style" attribute.
*
* @return bool
*/
public function isDisplayed()
{
return $this->executor->execute(
DriverCommand::IS_ELEMENT_DISPLAYED,
[':id' => $this->id]
);
}
/**
* Is the element currently enabled or not? This will generally return true
* for everything but disabled input elements.
*
* @return bool
*/
public function isEnabled()
{
return $this->executor->execute(
DriverCommand::IS_ELEMENT_ENABLED,
[':id' => $this->id]
);
}
/**
* Determine whether or not this element is selected or not.
*
* @return bool
*/
public function isSelected()
{
return $this->executor->execute(
DriverCommand::IS_ELEMENT_SELECTED,
[':id' => $this->id]
);
}
/**
* Simulate typing into an element, which may set its value.
*
* @param mixed $value The data to be typed.
* @return RemoteWebElement The current instance.
*/
public function sendKeys($value)
{
$local_file = $this->fileDetector->getLocalFile($value);
if ($local_file === null) {
$params = [
'value' => WebDriverKeys::encode($value),
':id' => $this->id,
];
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params);
} else {
$remote_path = $this->upload($local_file);
$params = [
'value' => WebDriverKeys::encode($remote_path),
':id' => $this->id,
];
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params);
}
return $this;
}
/**
* Set the fileDetector in order to let the RemoteWebElement to know that
* you are going to upload a file.
*
* Basically, if you want WebDriver trying to send a file, set the fileDetector
* to be LocalFileDetector. Otherwise, keep it UselessFileDetector.
*
* eg. `$element->setFileDetector(new LocalFileDetector);`
*
* @param FileDetector $detector
* @return RemoteWebElement
* @see FileDetector
* @see LocalFileDetector
* @see UselessFileDetector
*/
public function setFileDetector(FileDetector $detector)
{
$this->fileDetector = $detector;
return $this;
}
/**
* If this current element is a form, or an element within a form, then this will be submitted to the remote server.
*
* @return RemoteWebElement The current instance.
*/
public function submit()
{
$this->executor->execute(
DriverCommand::SUBMIT_ELEMENT,
[':id' => $this->id]
);
return $this;
}
/**
* Get the opaque ID of the element.
*
* @return string The opaque ID.
*/
public function getID()
{
return $this->id;
}
/**
* Test if two element IDs refer to the same DOM element.
*
* @param WebDriverElement $other
* @return bool
*/
public function equals(WebDriverElement $other)
{
return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, [
':id' => $this->id,
':other' => $other->getID(),
]);
}
/**
* Return the WebDriverElement with $id
*
* @param string $id
*
* @return static
*/
protected function newElement($id)
{
return new static($this->executor, $id);
}
/**
* Upload a local file to the server
*
* @param string $local_file
*
* @throws WebDriverException
* @return string The remote path of the file.
*/
protected function upload($local_file)
{
if (!is_file($local_file)) {
throw new WebDriverException('You may only upload files: ' . $local_file);
}
// Create a temporary file in the system temp directory.
$temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip');
$zip = new ZipArchive();
if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) {
return false;
}
$info = pathinfo($local_file);
$file_name = $info['basename'];
$zip->addFile($local_file, $file_name);
$zip->close();
$params = [
'file' => base64_encode(file_get_contents($temp_zip)),
];
$remote_path = $this->executor->execute(
DriverCommand::UPLOAD_FILE,
$params
);
unlink($temp_zip);
return $remote_path;
}
}

View File

@@ -0,0 +1,68 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote\Service;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\HttpCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;
use Facebook\WebDriver\Remote\WebDriverResponse;
/**
* A HttpCommandExecutor that talks to a local driver service instead of
* a remote server.
*/
class DriverCommandExecutor extends HttpCommandExecutor
{
/**
* @var DriverService
*/
private $service;
public function __construct(DriverService $service)
{
parent::__construct($service->getURL());
$this->service = $service;
}
/**
* @param WebDriverCommand $command
*
* @throws WebDriverException
* @throws \Exception
* @return WebDriverResponse
*/
public function execute(WebDriverCommand $command)
{
if ($command->getName() === DriverCommand::NEW_SESSION) {
$this->service->start();
}
try {
$value = parent::execute($command);
if ($command->getName() === DriverCommand::QUIT) {
$this->service->stop();
}
return $value;
} catch (\Exception $e) {
if (!$this->service->isRunning()) {
throw new WebDriverException('The driver server has died.');
}
throw $e;
}
}
}

View File

@@ -0,0 +1,164 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote\Service;
use Exception;
use Facebook\WebDriver\Net\URLChecker;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;
/**
* Start local WebDriver service (when remote WebDriver server is not used).
*/
class DriverService
{
/**
* @var string
*/
private $executable;
/**
* @var string
*/
private $url;
/**
* @var array
*/
private $args;
/**
* @var array
*/
private $environment;
/**
* @var Process|null
*/
private $process;
/**
* @param string $executable
* @param int $port The given port the service should use.
* @param array $args
* @param array|null $environment Use the system environment if it is null
*/
public function __construct($executable, $port, $args = [], $environment = null)
{
$this->executable = self::checkExecutable($executable);
$this->url = sprintf('http://localhost:%d', $port);
$this->args = $args;
$this->environment = $environment ?: $_ENV;
}
/**
* @return string
*/
public function getURL()
{
return $this->url;
}
/**
* @return DriverService
*/
public function start()
{
if ($this->process !== null) {
return $this;
}
$this->process = $this->createProcess();
$this->process->start();
$checker = new URLChecker();
$checker->waitUntilAvailable(20 * 1000, $this->url . '/status');
return $this;
}
/**
* @return DriverService
*/
public function stop()
{
if ($this->process === null) {
return $this;
}
$this->process->stop();
$this->process = null;
$checker = new URLChecker();
$checker->waitUntilUnavailable(3 * 1000, $this->url . '/shutdown');
return $this;
}
/**
* @return bool
*/
public function isRunning()
{
if ($this->process === null) {
return false;
}
return $this->process->isRunning();
}
/**
* Check if the executable is executable.
*
* @param string $executable
* @throws Exception
* @return string
*/
protected static function checkExecutable($executable)
{
if (!is_file($executable)) {
throw new Exception("'$executable' is not a file.");
}
if (!is_executable($executable)) {
throw new Exception("'$executable' is not executable.");
}
return $executable;
}
/**
* @return Process
*/
private function createProcess()
{
// BC: ProcessBuilder deprecated since Symfony 3.4 and removed in Symfony 4.0.
if (class_exists(ProcessBuilder::class)
&& false === mb_strpos('@deprecated', (new \ReflectionClass(ProcessBuilder::class))->getDocComment())
) {
$processBuilder = (new ProcessBuilder())
->setPrefix($this->executable)
->setArguments($this->args)
->addEnvironmentVariables($this->environment);
return $processBuilder->getProcess();
}
// Safe to use since Symfony 3.3
$commandLine = array_merge([$this->executable], $this->args);
return new Process($commandLine, null, $this->environment);
}
}

View File

@@ -0,0 +1,24 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
class UselessFileDetector implements FileDetector
{
public function getLocalFile($file)
{
return null;
}
}

View File

@@ -0,0 +1,49 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
/**
* All the browsers supported by selenium.
*
* @codeCoverageIgnore
*/
class WebDriverBrowserType
{
const FIREFOX = 'firefox';
const FIREFOX_PROXY = 'firefoxproxy';
const FIREFOX_CHROME = 'firefoxchrome';
const GOOGLECHROME = 'googlechrome';
const SAFARI = 'safari';
const SAFARI_PROXY = 'safariproxy';
const OPERA = 'opera';
const MICROSOFT_EDGE = 'MicrosoftEdge';
const IEXPLORE = 'iexplore';
const IEXPLORE_PROXY = 'iexploreproxy';
const CHROME = 'chrome';
const KONQUEROR = 'konqueror';
const MOCK = 'mock';
const IE_HTA = 'iehta';
const ANDROID = 'android';
const HTMLUNIT = 'htmlunit';
const IE = 'internet explorer';
const IPHONE = 'iphone';
const IPAD = 'iPad';
const PHANTOMJS = 'phantomjs';
private function __construct()
{
}
}

View File

@@ -0,0 +1,45 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
/**
* WebDriverCapabilityType contains all constants defined in the WebDriver Wire Protocol.
*
* @codeCoverageIgnore
*/
class WebDriverCapabilityType
{
const BROWSER_NAME = 'browserName';
const VERSION = 'version';
const PLATFORM = 'platform';
const JAVASCRIPT_ENABLED = 'javascriptEnabled';
const TAKES_SCREENSHOT = 'takesScreenshot';
const HANDLES_ALERTS = 'handlesAlerts';
const DATABASE_ENABLED = 'databaseEnabled';
const LOCATION_CONTEXT_ENABLED = 'locationContextEnabled';
const APPLICATION_CACHE_ENABLED = 'applicationCacheEnabled';
const BROWSER_CONNECTION_ENABLED = 'browserConnectionEnabled';
const CSS_SELECTORS_ENABLED = 'cssSelectorsEnabled';
const WEB_STORAGE_ENABLED = 'webStorageEnabled';
const ROTATABLE = 'rotatable';
const ACCEPT_SSL_CERTS = 'acceptSslCerts';
const NATIVE_EVENTS = 'nativeEvents';
const PROXY = 'proxy';
private function __construct()
{
}
}

View File

@@ -0,0 +1,62 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
class WebDriverCommand
{
/** @var string */
private $sessionID;
/** @var string */
private $name;
/** @var array */
private $parameters;
/**
* @param string $session_id
* @param string $name Constant from DriverCommand
* @param array $parameters Array of
*/
public function __construct($session_id, $name, $parameters)
{
$this->sessionID = $session_id;
$this->name = $name;
$this->parameters = $parameters;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getSessionID()
{
return $this->sessionID;
}
/**
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
}

View File

@@ -0,0 +1,97 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
//
// 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.
namespace Facebook\WebDriver\Remote;
class WebDriverResponse
{
/**
* @var int
*/
private $status;
/**
* @var mixed
*/
private $value;
/**
* @var string
*/
private $sessionID;
/**
* @param null|string $session_id
*/
public function __construct($session_id = null)
{
$this->sessionID = $session_id;
}
/**
* @return null|int
*/
public function getStatus()
{
return $this->status;
}
/**
* @param int $status
* @return WebDriverResponse
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @param mixed $value
* @return WebDriverResponse
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return null|string
*/
public function getSessionID()
{
return $this->sessionID;
}
/**
* @param mixed $session_id
* @return WebDriverResponse
*/
public function setSessionID($session_id)
{
$this->sessionID = $session_id;
return $this;
}
}