@@ -56,22 +56,19 @@ class RemoteWebDriver implements WebDriver, JavaScriptExecutor, WebDriverHasInpu
5656 /**
5757 * @param HttpCommandExecutor $commandExecutor
5858 * @param string $sessionId
59- * @param WebDriverCapabilities|null $capabilities
59+ * @param WebDriverCapabilities $capabilities
6060 * @param bool $isW3cCompliant false to use the legacy JsonWire protocol, true for the W3C WebDriver spec
6161 */
6262 protected function __construct (
6363 HttpCommandExecutor $ commandExecutor ,
6464 $ sessionId ,
65- WebDriverCapabilities $ capabilities = null ,
65+ WebDriverCapabilities $ capabilities ,
6666 $ isW3cCompliant = false
6767 ) {
6868 $ this ->executor = $ commandExecutor ;
6969 $ this ->sessionID = $ sessionId ;
7070 $ this ->isW3cCompliant = $ isW3cCompliant ;
71-
72- if ($ capabilities !== null ) {
73- $ this ->capabilities = $ capabilities ;
74- }
71+ $ this ->capabilities = $ capabilities ;
7572 }
7673
7774 /**
@@ -139,14 +136,22 @@ public static function create(
139136 /**
140137 * [Experimental] Construct the RemoteWebDriver by an existing session.
141138 *
142- * This constructor can boost the performance a lot by reusing the same browser for the whole test suite.
143- * You cannot pass the desired capabilities because the session was created before.
139+ * This constructor can boost the performance by reusing the same browser for the whole test suite. On the other
140+ * hand, because the browser is not pristine, this may lead to flaky and dependent tests. So carefully
141+ * consider the tradeoffs.
142+ *
143+ * To create the instance, we need to know Capabilities of the previously created session. You can either
144+ * pass them in $existingCapabilities parameter, or we will attempt to receive them from the Selenium Grid server.
145+ * However, if Capabilities were not provided and the attempt to get them was not successful,
146+ * exception will be thrown.
144147 *
145148 * @param string $session_id The existing session id
146149 * @param string $selenium_server_url The url of the remote Selenium WebDriver server
147150 * @param int|null $connection_timeout_in_ms Set timeout for the connect phase to remote Selenium WebDriver server
148151 * @param int|null $request_timeout_in_ms Set the maximum time of a request to remote Selenium WebDriver server
149152 * @param bool $isW3cCompliant True to use W3C WebDriver (default), false to use the legacy JsonWire protocol
153+ * @param WebDriverCapabilities|null $existingCapabilities Provide capabilities of the existing previously created
154+ * session. If not provided, we will attempt to read them, but this will only work when using Selenium Grid.
150155 * @return static
151156 */
152157 public static function createBySessionID (
@@ -157,6 +162,7 @@ public static function createBySessionID(
157162 ) {
158163 // BC layer to not break the method signature
159164 $ isW3cCompliant = func_num_args () > 4 ? func_get_arg (4 ) : true ;
165+ $ existingCapabilities = func_num_args () > 5 ? func_get_arg (5 ) : null ;
160166
161167 $ executor = new HttpCommandExecutor ($ selenium_server_url , null , null );
162168 if ($ connection_timeout_in_ms !== null ) {
@@ -170,7 +176,12 @@ public static function createBySessionID(
170176 $ executor ->disableW3cCompliance ();
171177 }
172178
173- return new static ($ executor , $ session_id , null , $ isW3cCompliant );
179+ // if capabilities were not provided, attempt to read them from the Selenium Grid API
180+ if ($ existingCapabilities === null ) {
181+ $ existingCapabilities = self ::readExistingCapabilitiesFromSeleniumGrid ($ session_id , $ executor );
182+ }
183+
184+ return new static ($ executor , $ session_id , $ existingCapabilities , $ isW3cCompliant );
174185 }
175186
176187 /**
@@ -727,4 +738,26 @@ protected static function castToDesiredCapabilitiesObject($desired_capabilities
727738
728739 return $ desired_capabilities ;
729740 }
741+
742+ protected static function readExistingCapabilitiesFromSeleniumGrid (
743+ string $ session_id ,
744+ HttpCommandExecutor $ executor
745+ ): DesiredCapabilities {
746+ $ getCapabilitiesCommand = new CustomWebDriverCommand ($ session_id , '/se/grid/session/:sessionId ' , 'GET ' , []);
747+
748+ try {
749+ $ capabilitiesResponse = $ executor ->execute ($ getCapabilitiesCommand );
750+
751+ $ existingCapabilities = DesiredCapabilities::createFromW3cCapabilities (
752+ $ capabilitiesResponse ->getValue ()['capabilities ' ]
753+ );
754+ if ($ existingCapabilities === null ) {
755+ throw UnexpectedResponseException::forError ('Empty capabilities received ' );
756+ }
757+ } catch (\Exception $ e ) {
758+ throw UnexpectedResponseException::forCapabilitiesRetrievalError ($ e );
759+ }
760+
761+ return $ existingCapabilities ;
762+ }
730763}
0 commit comments