xref: /plugin/combo/vendor/php-webdriver/webdriver/lib/Remote/RemoteWebDriver.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeaunamespace Facebook\WebDriver\Remote;
4*04fd306cSNickeau
5*04fd306cSNickeauuse Facebook\WebDriver\Interactions\WebDriverActions;
6*04fd306cSNickeauuse Facebook\WebDriver\JavaScriptExecutor;
7*04fd306cSNickeauuse Facebook\WebDriver\WebDriver;
8*04fd306cSNickeauuse Facebook\WebDriver\WebDriverBy;
9*04fd306cSNickeauuse Facebook\WebDriver\WebDriverCapabilities;
10*04fd306cSNickeauuse Facebook\WebDriver\WebDriverCommandExecutor;
11*04fd306cSNickeauuse Facebook\WebDriver\WebDriverElement;
12*04fd306cSNickeauuse Facebook\WebDriver\WebDriverHasInputDevices;
13*04fd306cSNickeauuse Facebook\WebDriver\WebDriverNavigation;
14*04fd306cSNickeauuse Facebook\WebDriver\WebDriverOptions;
15*04fd306cSNickeauuse Facebook\WebDriver\WebDriverWait;
16*04fd306cSNickeau
17*04fd306cSNickeauclass RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInputDevices
18*04fd306cSNickeau{
19*04fd306cSNickeau    /**
20*04fd306cSNickeau     * @var HttpCommandExecutor|null
21*04fd306cSNickeau     */
22*04fd306cSNickeau    protected $executor;
23*04fd306cSNickeau    /**
24*04fd306cSNickeau     * @var WebDriverCapabilities
25*04fd306cSNickeau     */
26*04fd306cSNickeau    protected $capabilities;
27*04fd306cSNickeau
28*04fd306cSNickeau    /**
29*04fd306cSNickeau     * @var string
30*04fd306cSNickeau     */
31*04fd306cSNickeau    protected $sessionID;
32*04fd306cSNickeau    /**
33*04fd306cSNickeau     * @var RemoteMouse
34*04fd306cSNickeau     */
35*04fd306cSNickeau    protected $mouse;
36*04fd306cSNickeau    /**
37*04fd306cSNickeau     * @var RemoteKeyboard
38*04fd306cSNickeau     */
39*04fd306cSNickeau    protected $keyboard;
40*04fd306cSNickeau    /**
41*04fd306cSNickeau     * @var RemoteTouchScreen
42*04fd306cSNickeau     */
43*04fd306cSNickeau    protected $touch;
44*04fd306cSNickeau    /**
45*04fd306cSNickeau     * @var RemoteExecuteMethod
46*04fd306cSNickeau     */
47*04fd306cSNickeau    protected $executeMethod;
48*04fd306cSNickeau    /**
49*04fd306cSNickeau     * @var bool
50*04fd306cSNickeau     */
51*04fd306cSNickeau    protected $isW3cCompliant;
52*04fd306cSNickeau
53*04fd306cSNickeau    /**
54*04fd306cSNickeau     * @param HttpCommandExecutor $commandExecutor
55*04fd306cSNickeau     * @param string $sessionId
56*04fd306cSNickeau     * @param WebDriverCapabilities|null $capabilities
57*04fd306cSNickeau     * @param bool $isW3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec
58*04fd306cSNickeau     */
59*04fd306cSNickeau    protected function __construct(
60*04fd306cSNickeau        HttpCommandExecutor $commandExecutor,
61*04fd306cSNickeau        $sessionId,
62*04fd306cSNickeau        WebDriverCapabilities $capabilities = null,
63*04fd306cSNickeau        $isW3cCompliant = false
64*04fd306cSNickeau    ) {
65*04fd306cSNickeau        $this->executor = $commandExecutor;
66*04fd306cSNickeau        $this->sessionID = $sessionId;
67*04fd306cSNickeau        $this->isW3cCompliant = $isW3cCompliant;
68*04fd306cSNickeau
69*04fd306cSNickeau        if ($capabilities !== null) {
70*04fd306cSNickeau            $this->capabilities = $capabilities;
71*04fd306cSNickeau        }
72*04fd306cSNickeau    }
73*04fd306cSNickeau
74*04fd306cSNickeau    /**
75*04fd306cSNickeau     * Construct the RemoteWebDriver by a desired capabilities.
76*04fd306cSNickeau     *
77*04fd306cSNickeau     * @param string $selenium_server_url The url of the remote Selenium WebDriver server
78*04fd306cSNickeau     * @param DesiredCapabilities|array $desired_capabilities The desired capabilities
79*04fd306cSNickeau     * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server
80*04fd306cSNickeau     * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server
81*04fd306cSNickeau     * @param string|null $http_proxy The proxy to tunnel requests to the remote Selenium WebDriver through
82*04fd306cSNickeau     * @param int|null $http_proxy_port The proxy port to tunnel requests to the remote Selenium WebDriver through
83*04fd306cSNickeau     * @param DesiredCapabilities $required_capabilities The required capabilities
84*04fd306cSNickeau     *
85*04fd306cSNickeau     * @return static
86*04fd306cSNickeau     */
87*04fd306cSNickeau    public static function create(
88*04fd306cSNickeau        $selenium_server_url = 'http://localhost:4444/wd/hub',
89*04fd306cSNickeau        $desired_capabilities = null,
90*04fd306cSNickeau        $connection_timeout_in_ms = null,
91*04fd306cSNickeau        $request_timeout_in_ms = null,
92*04fd306cSNickeau        $http_proxy = null,
93*04fd306cSNickeau        $http_proxy_port = null,
94*04fd306cSNickeau        DesiredCapabilities $required_capabilities = null
95*04fd306cSNickeau    ) {
96*04fd306cSNickeau        $selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url);
97*04fd306cSNickeau
98*04fd306cSNickeau        $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities);
99*04fd306cSNickeau
100*04fd306cSNickeau        $executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port);
101*04fd306cSNickeau        if ($connection_timeout_in_ms !== null) {
102*04fd306cSNickeau            $executor->setConnectionTimeout($connection_timeout_in_ms);
103*04fd306cSNickeau        }
104*04fd306cSNickeau        if ($request_timeout_in_ms !== null) {
105*04fd306cSNickeau            $executor->setRequestTimeout($request_timeout_in_ms);
106*04fd306cSNickeau        }
107*04fd306cSNickeau
108*04fd306cSNickeau        // W3C
109*04fd306cSNickeau        $parameters = [
110*04fd306cSNickeau            'capabilities' => [
111*04fd306cSNickeau                'firstMatch' => [(object) $desired_capabilities->toW3cCompatibleArray()],
112*04fd306cSNickeau            ],
113*04fd306cSNickeau        ];
114*04fd306cSNickeau
115*04fd306cSNickeau        if ($required_capabilities !== null && !empty($required_capabilities->toArray())) {
116*04fd306cSNickeau            $parameters['capabilities']['alwaysMatch'] = (object) $required_capabilities->toW3cCompatibleArray();
117*04fd306cSNickeau        }
118*04fd306cSNickeau
119*04fd306cSNickeau        // Legacy protocol
120*04fd306cSNickeau        if ($required_capabilities !== null) {
121*04fd306cSNickeau            // TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities.
122*04fd306cSNickeau            // This has changed with the W3C WebDriver spec, but is the only way how to pass these
123*04fd306cSNickeau            // values with the legacy protocol.
124*04fd306cSNickeau            $desired_capabilities->setCapability('requiredCapabilities', (object) $required_capabilities->toArray());
125*04fd306cSNickeau        }
126*04fd306cSNickeau
127*04fd306cSNickeau        $parameters['desiredCapabilities'] = (object) $desired_capabilities->toArray();
128*04fd306cSNickeau
129*04fd306cSNickeau        $command = WebDriverCommand::newSession($parameters);
130*04fd306cSNickeau
131*04fd306cSNickeau        $response = $executor->execute($command);
132*04fd306cSNickeau
133*04fd306cSNickeau        return static::createFromResponse($response, $executor);
134*04fd306cSNickeau    }
135*04fd306cSNickeau
136*04fd306cSNickeau    /**
137*04fd306cSNickeau     * [Experimental] Construct the RemoteWebDriver by an existing session.
138*04fd306cSNickeau     *
139*04fd306cSNickeau     * This constructor can boost the performance a lot by reusing the same browser for the whole test suite.
140*04fd306cSNickeau     * You cannot pass the desired capabilities because the session was created before.
141*04fd306cSNickeau     *
142*04fd306cSNickeau     * @param string $selenium_server_url The url of the remote Selenium WebDriver server
143*04fd306cSNickeau     * @param string $session_id The existing session id
144*04fd306cSNickeau     * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server
145*04fd306cSNickeau     * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server
146*04fd306cSNickeau     * @param bool $isW3cCompliant True to use W3C WebDriver (default), false to use the legacy JsonWire protocol
147*04fd306cSNickeau     * @return static
148*04fd306cSNickeau     */
149*04fd306cSNickeau    public static function createBySessionID(
150*04fd306cSNickeau        $session_id,
151*04fd306cSNickeau        $selenium_server_url = 'http://localhost:4444/wd/hub',
152*04fd306cSNickeau        $connection_timeout_in_ms = null,
153*04fd306cSNickeau        $request_timeout_in_ms = null
154*04fd306cSNickeau    ) {
155*04fd306cSNickeau        // BC layer to not break the method signature
156*04fd306cSNickeau        $isW3cCompliant = func_num_args() > 4 ? func_get_arg(4) : true;
157*04fd306cSNickeau
158*04fd306cSNickeau        $executor = new HttpCommandExecutor($selenium_server_url, null, null);
159*04fd306cSNickeau        if ($connection_timeout_in_ms !== null) {
160*04fd306cSNickeau            $executor->setConnectionTimeout($connection_timeout_in_ms);
161*04fd306cSNickeau        }
162*04fd306cSNickeau        if ($request_timeout_in_ms !== null) {
163*04fd306cSNickeau            $executor->setRequestTimeout($request_timeout_in_ms);
164*04fd306cSNickeau        }
165*04fd306cSNickeau
166*04fd306cSNickeau        if (!$isW3cCompliant) {
167*04fd306cSNickeau            $executor->disableW3cCompliance();
168*04fd306cSNickeau        }
169*04fd306cSNickeau
170*04fd306cSNickeau        return new static($executor, $session_id, null, $isW3cCompliant);
171*04fd306cSNickeau    }
172*04fd306cSNickeau
173*04fd306cSNickeau    /**
174*04fd306cSNickeau     * Close the current window.
175*04fd306cSNickeau     *
176*04fd306cSNickeau     * @return RemoteWebDriver The current instance.
177*04fd306cSNickeau     */
178*04fd306cSNickeau    public function close()
179*04fd306cSNickeau    {
180*04fd306cSNickeau        $this->execute(DriverCommand::CLOSE, []);
181*04fd306cSNickeau
182*04fd306cSNickeau        return $this;
183*04fd306cSNickeau    }
184*04fd306cSNickeau
185*04fd306cSNickeau    /**
186*04fd306cSNickeau     * Create a new top-level browsing context.
187*04fd306cSNickeau     *
188*04fd306cSNickeau     * @codeCoverageIgnore
189*04fd306cSNickeau     * @deprecated Use $driver->switchTo()->newWindow()
190*04fd306cSNickeau     * @return WebDriver The current instance.
191*04fd306cSNickeau     */
192*04fd306cSNickeau    public function newWindow()
193*04fd306cSNickeau    {
194*04fd306cSNickeau        return $this->switchTo()->newWindow();
195*04fd306cSNickeau    }
196*04fd306cSNickeau
197*04fd306cSNickeau    /**
198*04fd306cSNickeau     * Find the first WebDriverElement using the given mechanism.
199*04fd306cSNickeau     *
200*04fd306cSNickeau     * @param WebDriverBy $by
201*04fd306cSNickeau     * @return RemoteWebElement NoSuchElementException is thrown in HttpCommandExecutor if no element is found.
202*04fd306cSNickeau     * @see WebDriverBy
203*04fd306cSNickeau     */
204*04fd306cSNickeau    public function findElement(WebDriverBy $by)
205*04fd306cSNickeau    {
206*04fd306cSNickeau        $raw_element = $this->execute(
207*04fd306cSNickeau            DriverCommand::FIND_ELEMENT,
208*04fd306cSNickeau            JsonWireCompat::getUsing($by, $this->isW3cCompliant)
209*04fd306cSNickeau        );
210*04fd306cSNickeau
211*04fd306cSNickeau        return $this->newElement(JsonWireCompat::getElement($raw_element));
212*04fd306cSNickeau    }
213*04fd306cSNickeau
214*04fd306cSNickeau    /**
215*04fd306cSNickeau     * Find all WebDriverElements within the current page using the given mechanism.
216*04fd306cSNickeau     *
217*04fd306cSNickeau     * @param WebDriverBy $by
218*04fd306cSNickeau     * @return RemoteWebElement[] A list of all WebDriverElements, or an empty array if nothing matches
219*04fd306cSNickeau     * @see WebDriverBy
220*04fd306cSNickeau     */
221*04fd306cSNickeau    public function findElements(WebDriverBy $by)
222*04fd306cSNickeau    {
223*04fd306cSNickeau        $raw_elements = $this->execute(
224*04fd306cSNickeau            DriverCommand::FIND_ELEMENTS,
225*04fd306cSNickeau            JsonWireCompat::getUsing($by, $this->isW3cCompliant)
226*04fd306cSNickeau        );
227*04fd306cSNickeau
228*04fd306cSNickeau        $elements = [];
229*04fd306cSNickeau        foreach ($raw_elements as $raw_element) {
230*04fd306cSNickeau            $elements[] = $this->newElement(JsonWireCompat::getElement($raw_element));
231*04fd306cSNickeau        }
232*04fd306cSNickeau
233*04fd306cSNickeau        return $elements;
234*04fd306cSNickeau    }
235*04fd306cSNickeau
236*04fd306cSNickeau    /**
237*04fd306cSNickeau     * Load a new web page in the current browser window.
238*04fd306cSNickeau     *
239*04fd306cSNickeau     * @param string $url
240*04fd306cSNickeau     *
241*04fd306cSNickeau     * @return RemoteWebDriver The current instance.
242*04fd306cSNickeau     */
243*04fd306cSNickeau    public function get($url)
244*04fd306cSNickeau    {
245*04fd306cSNickeau        $params = ['url' => (string) $url];
246*04fd306cSNickeau        $this->execute(DriverCommand::GET, $params);
247*04fd306cSNickeau
248*04fd306cSNickeau        return $this;
249*04fd306cSNickeau    }
250*04fd306cSNickeau
251*04fd306cSNickeau    /**
252*04fd306cSNickeau     * Get a string representing the current URL that the browser is looking at.
253*04fd306cSNickeau     *
254*04fd306cSNickeau     * @return string The current URL.
255*04fd306cSNickeau     */
256*04fd306cSNickeau    public function getCurrentURL()
257*04fd306cSNickeau    {
258*04fd306cSNickeau        return $this->execute(DriverCommand::GET_CURRENT_URL);
259*04fd306cSNickeau    }
260*04fd306cSNickeau
261*04fd306cSNickeau    /**
262*04fd306cSNickeau     * Get the source of the last loaded page.
263*04fd306cSNickeau     *
264*04fd306cSNickeau     * @return string The current page source.
265*04fd306cSNickeau     */
266*04fd306cSNickeau    public function getPageSource()
267*04fd306cSNickeau    {
268*04fd306cSNickeau        return $this->execute(DriverCommand::GET_PAGE_SOURCE);
269*04fd306cSNickeau    }
270*04fd306cSNickeau
271*04fd306cSNickeau    /**
272*04fd306cSNickeau     * Get the title of the current page.
273*04fd306cSNickeau     *
274*04fd306cSNickeau     * @return string The title of the current page.
275*04fd306cSNickeau     */
276*04fd306cSNickeau    public function getTitle()
277*04fd306cSNickeau    {
278*04fd306cSNickeau        return $this->execute(DriverCommand::GET_TITLE);
279*04fd306cSNickeau    }
280*04fd306cSNickeau
281*04fd306cSNickeau    /**
282*04fd306cSNickeau     * Return an opaque handle to this window that uniquely identifies it within this driver instance.
283*04fd306cSNickeau     *
284*04fd306cSNickeau     * @return string The current window handle.
285*04fd306cSNickeau     */
286*04fd306cSNickeau    public function getWindowHandle()
287*04fd306cSNickeau    {
288*04fd306cSNickeau        return $this->execute(
289*04fd306cSNickeau            DriverCommand::GET_CURRENT_WINDOW_HANDLE,
290*04fd306cSNickeau            []
291*04fd306cSNickeau        );
292*04fd306cSNickeau    }
293*04fd306cSNickeau
294*04fd306cSNickeau    /**
295*04fd306cSNickeau     * Get all window handles available to the current session.
296*04fd306cSNickeau     *
297*04fd306cSNickeau     * Note: Do not use `end($driver->getWindowHandles())` to find the last open window, for proper solution see:
298*04fd306cSNickeau     * https://github.com/php-webdriver/php-webdriver/wiki/Alert,-tabs,-frames,-iframes#switch-to-the-new-window
299*04fd306cSNickeau     *
300*04fd306cSNickeau     * @return array An array of string containing all available window handles.
301*04fd306cSNickeau     */
302*04fd306cSNickeau    public function getWindowHandles()
303*04fd306cSNickeau    {
304*04fd306cSNickeau        return $this->execute(DriverCommand::GET_WINDOW_HANDLES, []);
305*04fd306cSNickeau    }
306*04fd306cSNickeau
307*04fd306cSNickeau    /**
308*04fd306cSNickeau     * Quits this driver, closing every associated window.
309*04fd306cSNickeau     */
310*04fd306cSNickeau    public function quit()
311*04fd306cSNickeau    {
312*04fd306cSNickeau        $this->execute(DriverCommand::QUIT);
313*04fd306cSNickeau        $this->executor = null;
314*04fd306cSNickeau    }
315*04fd306cSNickeau
316*04fd306cSNickeau    /**
317*04fd306cSNickeau     * Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.
318*04fd306cSNickeau     * The executed script is assumed to be synchronous and the result of evaluating the script will be returned.
319*04fd306cSNickeau     *
320*04fd306cSNickeau     * @param string $script The script to inject.
321*04fd306cSNickeau     * @param array $arguments The arguments of the script.
322*04fd306cSNickeau     * @return mixed The return value of the script.
323*04fd306cSNickeau     */
324*04fd306cSNickeau    public function executeScript($script, array $arguments = [])
325*04fd306cSNickeau    {
326*04fd306cSNickeau        $params = [
327*04fd306cSNickeau            'script' => $script,
328*04fd306cSNickeau            'args' => $this->prepareScriptArguments($arguments),
329*04fd306cSNickeau        ];
330*04fd306cSNickeau
331*04fd306cSNickeau        return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params);
332*04fd306cSNickeau    }
333*04fd306cSNickeau
334*04fd306cSNickeau    /**
335*04fd306cSNickeau     * Inject a snippet of JavaScript into the page for asynchronous execution in the context of the currently selected
336*04fd306cSNickeau     * frame.
337*04fd306cSNickeau     *
338*04fd306cSNickeau     * The driver will pass a callback as the last argument to the snippet, and block until the callback is invoked.
339*04fd306cSNickeau     *
340*04fd306cSNickeau     * You may need to define script timeout using `setScriptTimeout()` method of `WebDriverTimeouts` first.
341*04fd306cSNickeau     *
342*04fd306cSNickeau     * @param string $script The script to inject.
343*04fd306cSNickeau     * @param array $arguments The arguments of the script.
344*04fd306cSNickeau     * @return mixed The value passed by the script to the callback.
345*04fd306cSNickeau     */
346*04fd306cSNickeau    public function executeAsyncScript($script, array $arguments = [])
347*04fd306cSNickeau    {
348*04fd306cSNickeau        $params = [
349*04fd306cSNickeau            'script' => $script,
350*04fd306cSNickeau            'args' => $this->prepareScriptArguments($arguments),
351*04fd306cSNickeau        ];
352*04fd306cSNickeau
353*04fd306cSNickeau        return $this->execute(
354*04fd306cSNickeau            DriverCommand::EXECUTE_ASYNC_SCRIPT,
355*04fd306cSNickeau            $params
356*04fd306cSNickeau        );
357*04fd306cSNickeau    }
358*04fd306cSNickeau
359*04fd306cSNickeau    /**
360*04fd306cSNickeau     * Take a screenshot of the current page.
361*04fd306cSNickeau     *
362*04fd306cSNickeau     * @param string $save_as The path of the screenshot to be saved.
363*04fd306cSNickeau     * @return string The screenshot in PNG format.
364*04fd306cSNickeau     */
365*04fd306cSNickeau    public function takeScreenshot($save_as = null)
366*04fd306cSNickeau    {
367*04fd306cSNickeau        $screenshot = base64_decode($this->execute(DriverCommand::SCREENSHOT), true);
368*04fd306cSNickeau
369*04fd306cSNickeau        if ($save_as !== null) {
370*04fd306cSNickeau            $directoryPath = dirname($save_as);
371*04fd306cSNickeau
372*04fd306cSNickeau            if (!file_exists($directoryPath)) {
373*04fd306cSNickeau                mkdir($directoryPath, 0777, true);
374*04fd306cSNickeau            }
375*04fd306cSNickeau
376*04fd306cSNickeau            file_put_contents($save_as, $screenshot);
377*04fd306cSNickeau        }
378*04fd306cSNickeau
379*04fd306cSNickeau        return $screenshot;
380*04fd306cSNickeau    }
381*04fd306cSNickeau
382*04fd306cSNickeau    /**
383*04fd306cSNickeau     * Status returns information about whether a remote end is in a state in which it can create new sessions.
384*04fd306cSNickeau     */
385*04fd306cSNickeau    public function getStatus()
386*04fd306cSNickeau    {
387*04fd306cSNickeau        $response = $this->execute(DriverCommand::STATUS);
388*04fd306cSNickeau
389*04fd306cSNickeau        return RemoteStatus::createFromResponse($response);
390*04fd306cSNickeau    }
391*04fd306cSNickeau
392*04fd306cSNickeau    /**
393*04fd306cSNickeau     * Construct a new WebDriverWait by the current WebDriver instance.
394*04fd306cSNickeau     * Sample usage:
395*04fd306cSNickeau     *
396*04fd306cSNickeau     * ```
397*04fd306cSNickeau     *   $driver->wait(20, 1000)->until(
398*04fd306cSNickeau     *     WebDriverExpectedCondition::titleIs('WebDriver Page')
399*04fd306cSNickeau     *   );
400*04fd306cSNickeau     * ```
401*04fd306cSNickeau     * @param int $timeout_in_second
402*04fd306cSNickeau     * @param int $interval_in_millisecond
403*04fd306cSNickeau     *
404*04fd306cSNickeau     * @return WebDriverWait
405*04fd306cSNickeau     */
406*04fd306cSNickeau    public function wait($timeout_in_second = 30, $interval_in_millisecond = 250)
407*04fd306cSNickeau    {
408*04fd306cSNickeau        return new WebDriverWait(
409*04fd306cSNickeau            $this,
410*04fd306cSNickeau            $timeout_in_second,
411*04fd306cSNickeau            $interval_in_millisecond
412*04fd306cSNickeau        );
413*04fd306cSNickeau    }
414*04fd306cSNickeau
415*04fd306cSNickeau    /**
416*04fd306cSNickeau     * An abstraction for managing stuff you would do in a browser menu. For example, adding and deleting cookies.
417*04fd306cSNickeau     *
418*04fd306cSNickeau     * @return WebDriverOptions
419*04fd306cSNickeau     */
420*04fd306cSNickeau    public function manage()
421*04fd306cSNickeau    {
422*04fd306cSNickeau        return new WebDriverOptions($this->getExecuteMethod(), $this->isW3cCompliant);
423*04fd306cSNickeau    }
424*04fd306cSNickeau
425*04fd306cSNickeau    /**
426*04fd306cSNickeau     * An abstraction allowing the driver to access the browser's history and to navigate to a given URL.
427*04fd306cSNickeau     *
428*04fd306cSNickeau     * @return WebDriverNavigation
429*04fd306cSNickeau     * @see WebDriverNavigation
430*04fd306cSNickeau     */
431*04fd306cSNickeau    public function navigate()
432*04fd306cSNickeau    {
433*04fd306cSNickeau        return new WebDriverNavigation($this->getExecuteMethod());
434*04fd306cSNickeau    }
435*04fd306cSNickeau
436*04fd306cSNickeau    /**
437*04fd306cSNickeau     * Switch to a different window or frame.
438*04fd306cSNickeau     *
439*04fd306cSNickeau     * @return RemoteTargetLocator
440*04fd306cSNickeau     * @see RemoteTargetLocator
441*04fd306cSNickeau     */
442*04fd306cSNickeau    public function switchTo()
443*04fd306cSNickeau    {
444*04fd306cSNickeau        return new RemoteTargetLocator($this->getExecuteMethod(), $this, $this->isW3cCompliant);
445*04fd306cSNickeau    }
446*04fd306cSNickeau
447*04fd306cSNickeau    /**
448*04fd306cSNickeau     * @return RemoteMouse
449*04fd306cSNickeau     */
450*04fd306cSNickeau    public function getMouse()
451*04fd306cSNickeau    {
452*04fd306cSNickeau        if (!$this->mouse) {
453*04fd306cSNickeau            $this->mouse = new RemoteMouse($this->getExecuteMethod(), $this->isW3cCompliant);
454*04fd306cSNickeau        }
455*04fd306cSNickeau
456*04fd306cSNickeau        return $this->mouse;
457*04fd306cSNickeau    }
458*04fd306cSNickeau
459*04fd306cSNickeau    /**
460*04fd306cSNickeau     * @return RemoteKeyboard
461*04fd306cSNickeau     */
462*04fd306cSNickeau    public function getKeyboard()
463*04fd306cSNickeau    {
464*04fd306cSNickeau        if (!$this->keyboard) {
465*04fd306cSNickeau            $this->keyboard = new RemoteKeyboard($this->getExecuteMethod(), $this, $this->isW3cCompliant);
466*04fd306cSNickeau        }
467*04fd306cSNickeau
468*04fd306cSNickeau        return $this->keyboard;
469*04fd306cSNickeau    }
470*04fd306cSNickeau
471*04fd306cSNickeau    /**
472*04fd306cSNickeau     * @return RemoteTouchScreen
473*04fd306cSNickeau     */
474*04fd306cSNickeau    public function getTouch()
475*04fd306cSNickeau    {
476*04fd306cSNickeau        if (!$this->touch) {
477*04fd306cSNickeau            $this->touch = new RemoteTouchScreen($this->getExecuteMethod());
478*04fd306cSNickeau        }
479*04fd306cSNickeau
480*04fd306cSNickeau        return $this->touch;
481*04fd306cSNickeau    }
482*04fd306cSNickeau
483*04fd306cSNickeau    /**
484*04fd306cSNickeau     * Construct a new action builder.
485*04fd306cSNickeau     *
486*04fd306cSNickeau     * @return WebDriverActions
487*04fd306cSNickeau     */
488*04fd306cSNickeau    public function action()
489*04fd306cSNickeau    {
490*04fd306cSNickeau        return new WebDriverActions($this);
491*04fd306cSNickeau    }
492*04fd306cSNickeau
493*04fd306cSNickeau    /**
494*04fd306cSNickeau     * Set the command executor of this RemoteWebdriver
495*04fd306cSNickeau     *
496*04fd306cSNickeau     * @deprecated To be removed in the future. Executor should be passed in the constructor.
497*04fd306cSNickeau     * @internal
498*04fd306cSNickeau     * @codeCoverageIgnore
499*04fd306cSNickeau     * @param WebDriverCommandExecutor $executor Despite the typehint, it have be an instance of HttpCommandExecutor.
500*04fd306cSNickeau     * @return RemoteWebDriver
501*04fd306cSNickeau     */
502*04fd306cSNickeau    public function setCommandExecutor(WebDriverCommandExecutor $executor)
503*04fd306cSNickeau    {
504*04fd306cSNickeau        $this->executor = $executor;
505*04fd306cSNickeau
506*04fd306cSNickeau        return $this;
507*04fd306cSNickeau    }
508*04fd306cSNickeau
509*04fd306cSNickeau    /**
510*04fd306cSNickeau     * Get the command executor of this RemoteWebdriver
511*04fd306cSNickeau     *
512*04fd306cSNickeau     * @return HttpCommandExecutor
513*04fd306cSNickeau     */
514*04fd306cSNickeau    public function getCommandExecutor()
515*04fd306cSNickeau    {
516*04fd306cSNickeau        return $this->executor;
517*04fd306cSNickeau    }
518*04fd306cSNickeau
519*04fd306cSNickeau    /**
520*04fd306cSNickeau     * Set the session id of the RemoteWebDriver.
521*04fd306cSNickeau     *
522*04fd306cSNickeau     * @deprecated To be removed in the future. Session ID should be passed in the constructor.
523*04fd306cSNickeau     * @internal
524*04fd306cSNickeau     * @codeCoverageIgnore
525*04fd306cSNickeau     * @param string $session_id
526*04fd306cSNickeau     * @return RemoteWebDriver
527*04fd306cSNickeau     */
528*04fd306cSNickeau    public function setSessionID($session_id)
529*04fd306cSNickeau    {
530*04fd306cSNickeau        $this->sessionID = $session_id;
531*04fd306cSNickeau
532*04fd306cSNickeau        return $this;
533*04fd306cSNickeau    }
534*04fd306cSNickeau
535*04fd306cSNickeau    /**
536*04fd306cSNickeau     * Get current selenium sessionID
537*04fd306cSNickeau     *
538*04fd306cSNickeau     * @return string
539*04fd306cSNickeau     */
540*04fd306cSNickeau    public function getSessionID()
541*04fd306cSNickeau    {
542*04fd306cSNickeau        return $this->sessionID;
543*04fd306cSNickeau    }
544*04fd306cSNickeau
545*04fd306cSNickeau    /**
546*04fd306cSNickeau     * Get capabilities of the RemoteWebDriver.
547*04fd306cSNickeau     *
548*04fd306cSNickeau     * @return WebDriverCapabilities
549*04fd306cSNickeau     */
550*04fd306cSNickeau    public function getCapabilities()
551*04fd306cSNickeau    {
552*04fd306cSNickeau        return $this->capabilities;
553*04fd306cSNickeau    }
554*04fd306cSNickeau
555*04fd306cSNickeau    /**
556*04fd306cSNickeau     * Returns a list of the currently active sessions.
557*04fd306cSNickeau     *
558*04fd306cSNickeau     * @param string $selenium_server_url The url of the remote Selenium WebDriver server
559*04fd306cSNickeau     * @param int $timeout_in_ms
560*04fd306cSNickeau     * @return array
561*04fd306cSNickeau     */
562*04fd306cSNickeau    public static function getAllSessions($selenium_server_url = 'http://localhost:4444/wd/hub', $timeout_in_ms = 30000)
563*04fd306cSNickeau    {
564*04fd306cSNickeau        $executor = new HttpCommandExecutor($selenium_server_url, null, null);
565*04fd306cSNickeau        $executor->setConnectionTimeout($timeout_in_ms);
566*04fd306cSNickeau
567*04fd306cSNickeau        $command = new WebDriverCommand(
568*04fd306cSNickeau            null,
569*04fd306cSNickeau            DriverCommand::GET_ALL_SESSIONS,
570*04fd306cSNickeau            []
571*04fd306cSNickeau        );
572*04fd306cSNickeau
573*04fd306cSNickeau        return $executor->execute($command)->getValue();
574*04fd306cSNickeau    }
575*04fd306cSNickeau
576*04fd306cSNickeau    public function execute($command_name, $params = [])
577*04fd306cSNickeau    {
578*04fd306cSNickeau        $command = new WebDriverCommand(
579*04fd306cSNickeau            $this->sessionID,
580*04fd306cSNickeau            $command_name,
581*04fd306cSNickeau            $params
582*04fd306cSNickeau        );
583*04fd306cSNickeau
584*04fd306cSNickeau        if ($this->executor) {
585*04fd306cSNickeau            $response = $this->executor->execute($command);
586*04fd306cSNickeau
587*04fd306cSNickeau            return $response->getValue();
588*04fd306cSNickeau        }
589*04fd306cSNickeau
590*04fd306cSNickeau        return null;
591*04fd306cSNickeau    }
592*04fd306cSNickeau
593*04fd306cSNickeau    /**
594*04fd306cSNickeau     * Execute custom commands on remote end.
595*04fd306cSNickeau     * For example vendor-specific commands or other commands not implemented by php-webdriver.
596*04fd306cSNickeau     *
597*04fd306cSNickeau     * @see https://github.com/php-webdriver/php-webdriver/wiki/Custom-commands
598*04fd306cSNickeau     * @param string $endpointUrl
599*04fd306cSNickeau     * @param string $method
600*04fd306cSNickeau     * @param array $params
601*04fd306cSNickeau     * @return mixed|null
602*04fd306cSNickeau     */
603*04fd306cSNickeau    public function executeCustomCommand($endpointUrl, $method = 'GET', $params = [])
604*04fd306cSNickeau    {
605*04fd306cSNickeau        $command = new CustomWebDriverCommand(
606*04fd306cSNickeau            $this->sessionID,
607*04fd306cSNickeau            $endpointUrl,
608*04fd306cSNickeau            $method,
609*04fd306cSNickeau            $params
610*04fd306cSNickeau        );
611*04fd306cSNickeau
612*04fd306cSNickeau        if ($this->executor) {
613*04fd306cSNickeau            $response = $this->executor->execute($command);
614*04fd306cSNickeau
615*04fd306cSNickeau            return $response->getValue();
616*04fd306cSNickeau        }
617*04fd306cSNickeau
618*04fd306cSNickeau        return null;
619*04fd306cSNickeau    }
620*04fd306cSNickeau
621*04fd306cSNickeau    /**
622*04fd306cSNickeau     * @internal
623*04fd306cSNickeau     * @return bool
624*04fd306cSNickeau     */
625*04fd306cSNickeau    public function isW3cCompliant()
626*04fd306cSNickeau    {
627*04fd306cSNickeau        return $this->isW3cCompliant;
628*04fd306cSNickeau    }
629*04fd306cSNickeau
630*04fd306cSNickeau    /**
631*04fd306cSNickeau     * Create instance based on response to NEW_SESSION command.
632*04fd306cSNickeau     * Also detect W3C/OSS dialect and setup the driver/executor accordingly.
633*04fd306cSNickeau     *
634*04fd306cSNickeau     * @internal
635*04fd306cSNickeau     * @return static
636*04fd306cSNickeau     */
637*04fd306cSNickeau    protected static function createFromResponse(WebDriverResponse $response, HttpCommandExecutor $commandExecutor)
638*04fd306cSNickeau    {
639*04fd306cSNickeau        $responseValue = $response->getValue();
640*04fd306cSNickeau
641*04fd306cSNickeau        if (!$isW3cCompliant = isset($responseValue['capabilities'])) {
642*04fd306cSNickeau            $commandExecutor->disableW3cCompliance();
643*04fd306cSNickeau        }
644*04fd306cSNickeau
645*04fd306cSNickeau        if ($isW3cCompliant) {
646*04fd306cSNickeau            $returnedCapabilities = DesiredCapabilities::createFromW3cCapabilities($responseValue['capabilities']);
647*04fd306cSNickeau        } else {
648*04fd306cSNickeau            $returnedCapabilities = new DesiredCapabilities($responseValue);
649*04fd306cSNickeau        }
650*04fd306cSNickeau
651*04fd306cSNickeau        return new static($commandExecutor, $response->getSessionID(), $returnedCapabilities, $isW3cCompliant);
652*04fd306cSNickeau    }
653*04fd306cSNickeau
654*04fd306cSNickeau    /**
655*04fd306cSNickeau     * Prepare arguments for JavaScript injection
656*04fd306cSNickeau     *
657*04fd306cSNickeau     * @param array $arguments
658*04fd306cSNickeau     * @return array
659*04fd306cSNickeau     */
660*04fd306cSNickeau    protected function prepareScriptArguments(array $arguments)
661*04fd306cSNickeau    {
662*04fd306cSNickeau        $args = [];
663*04fd306cSNickeau        foreach ($arguments as $key => $value) {
664*04fd306cSNickeau            if ($value instanceof WebDriverElement) {
665*04fd306cSNickeau                $args[$key] = [
666*04fd306cSNickeau                    $this->isW3cCompliant ?
667*04fd306cSNickeau                        JsonWireCompat::WEB_DRIVER_ELEMENT_IDENTIFIER
668*04fd306cSNickeau                        : 'ELEMENT' => $value->getID(),
669*04fd306cSNickeau                ];
670*04fd306cSNickeau            } else {
671*04fd306cSNickeau                if (is_array($value)) {
672*04fd306cSNickeau                    $value = $this->prepareScriptArguments($value);
673*04fd306cSNickeau                }
674*04fd306cSNickeau                $args[$key] = $value;
675*04fd306cSNickeau            }
676*04fd306cSNickeau        }
677*04fd306cSNickeau
678*04fd306cSNickeau        return $args;
679*04fd306cSNickeau    }
680*04fd306cSNickeau
681*04fd306cSNickeau    /**
682*04fd306cSNickeau     * @return RemoteExecuteMethod
683*04fd306cSNickeau     */
684*04fd306cSNickeau    protected function getExecuteMethod()
685*04fd306cSNickeau    {
686*04fd306cSNickeau        if (!$this->executeMethod) {
687*04fd306cSNickeau            $this->executeMethod = new RemoteExecuteMethod($this);
688*04fd306cSNickeau        }
689*04fd306cSNickeau
690*04fd306cSNickeau        return $this->executeMethod;
691*04fd306cSNickeau    }
692*04fd306cSNickeau
693*04fd306cSNickeau    /**
694*04fd306cSNickeau     * Return the WebDriverElement with the given id.
695*04fd306cSNickeau     *
696*04fd306cSNickeau     * @param string $id The id of the element to be created.
697*04fd306cSNickeau     * @return RemoteWebElement
698*04fd306cSNickeau     */
699*04fd306cSNickeau    protected function newElement($id)
700*04fd306cSNickeau    {
701*04fd306cSNickeau        return new RemoteWebElement($this->getExecuteMethod(), $id, $this->isW3cCompliant);
702*04fd306cSNickeau    }
703*04fd306cSNickeau
704*04fd306cSNickeau    /**
705*04fd306cSNickeau     * Cast legacy types (array or null) to DesiredCapabilities object. To be removed in future when instance of
706*04fd306cSNickeau     * DesiredCapabilities will be required.
707*04fd306cSNickeau     *
708*04fd306cSNickeau     * @param array|DesiredCapabilities|null $desired_capabilities
709*04fd306cSNickeau     * @return DesiredCapabilities
710*04fd306cSNickeau     */
711*04fd306cSNickeau    protected static function castToDesiredCapabilitiesObject($desired_capabilities = null)
712*04fd306cSNickeau    {
713*04fd306cSNickeau        if ($desired_capabilities === null) {
714*04fd306cSNickeau            return new DesiredCapabilities();
715*04fd306cSNickeau        }
716*04fd306cSNickeau
717*04fd306cSNickeau        if (is_array($desired_capabilities)) {
718*04fd306cSNickeau            return new DesiredCapabilities($desired_capabilities);
719*04fd306cSNickeau        }
720*04fd306cSNickeau
721*04fd306cSNickeau        return $desired_capabilities;
722*04fd306cSNickeau    }
723*04fd306cSNickeau}
724