Skip to content

Commit 3ad018a

Browse files
committed
Merge branch '0.x' into 'master'
2 parents ecba49b + 3b82736 commit 3ad018a

File tree

3 files changed

+92
-9
lines changed

3 files changed

+92
-9
lines changed

CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
- No description yet.
1414

15+
## [0.4.0] - 2021-02-25
16+
17+
### Added
18+
19+
- `ClientInterface::getSessionIdentifiers()` implementation to get a list with WebDriver sessions from the active pool
20+
(as an opportunity to resume existing sessions).
21+
22+
### Fixed
23+
24+
- Missed type checks after WebDriver response deserialization for some methods (e.g. to prevent misreading an
25+
error array as a valid command output).
26+
1527
## [0.3.0] - 2021-02-11
1628

1729
### Added
@@ -106,7 +118,8 @@ browser instance).
106118
This early development version doesn't yet contain full implementation for the introduced `WebDriverInterface`, only
107119
core design solutions and library interfaces are defined.
108120

109-
[Unreleased]: https://github.com/itnelo/reactphp-webdriver/compare/0.3.0...0.x
121+
[Unreleased]: https://github.com/itnelo/reactphp-webdriver/compare/0.4.0...0.x
122+
[0.4.0]: https://github.com/itnelo/reactphp-webdriver/compare/0.3.0..0.4.0
110123
[0.3.0]: https://github.com/itnelo/reactphp-webdriver/compare/0.2.1..0.3.0
111124
[0.2.1]: https://github.com/itnelo/reactphp-webdriver/compare/0.2.0..0.2.1
112125
[0.2.0]: https://github.com/itnelo/reactphp-webdriver/compare/0.1.0..0.2.0

src/Client/W3CClient.php

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939
*/
4040
class W3CClient implements ClientInterface
4141
{
42+
/**
43+
* A pattern to recognize session identifier in the WebDriver response
44+
*
45+
* @var string
46+
*/
47+
private const PATTERN_SESSION_IDENTIFIER = '/[":\s]+([a-z\d]{32})/Ui';
48+
4249
/**
4350
* Sends commands to the Selenium Grid endpoint using W3C protocol over HTTP
4451
*
@@ -116,9 +123,44 @@ function (OptionsResolver $serverOptionsResolver) {
116123
*/
117124
public function getSessionIdentifiers(): PromiseInterface
118125
{
119-
// todo: implementation
126+
$requestUri = sprintf(
127+
'http://%s:%d/wd/hub/sessions',
128+
$this->_options['server']['host'],
129+
$this->_options['server']['port']
130+
);
120131

121-
return reject(new RuntimeException('Not implemented.'));
132+
$requestHeaders = [
133+
'Content-Type' => 'application/json; charset=UTF-8',
134+
];
135+
136+
$responsePromise = $this->httpClient->get($requestUri, $requestHeaders);
137+
138+
$identifierListPromise = $responsePromise
139+
->then(
140+
function (ResponseInterface $response) {
141+
$dataArray = $this->deserializeResponse($response);
142+
$payload = $dataArray['message'] ?? '';
143+
144+
preg_match_all(self::PATTERN_SESSION_IDENTIFIER, $payload, $matches);
145+
146+
if (!isset($matches[1]) || 1 > count($matches[1])) {
147+
throw new RuntimeException('Unable to locate a list of session identifiers in the response.');
148+
}
149+
150+
$identifierList = $matches[1];
151+
152+
return $identifierList;
153+
}
154+
)
155+
->then(
156+
null,
157+
function (Throwable $rejectionReason) {
158+
throw new RuntimeException('Unable to get a list of session identifiers.', 0, $rejectionReason);
159+
}
160+
)
161+
;
162+
163+
return $identifierListPromise;
122164
}
123165

124166
/**
@@ -148,7 +190,7 @@ public function createSession(): PromiseInterface
148190
function (ResponseInterface $response) use ($sessionOpeningDeferred) {
149191
try {
150192
$responseBody = (string) $response->getBody();
151-
preg_match('/sessionid[":\s]+([a-z\d]{32})/Ui', $responseBody, $matches);
193+
preg_match(self::PATTERN_SESSION_IDENTIFIER, $responseBody, $matches);
152194

153195
if (!isset($matches[1])) {
154196
// todo: locate an error message or set it as "undefined error"
@@ -235,6 +277,10 @@ function (ResponseInterface $response) use ($tabLookupDeferred) {
235277
try {
236278
$tabIdentifiers = $this->deserializeResponse($response);
237279

280+
if (!is_array($tabIdentifiers)) {
281+
throw new RuntimeException('Unable to locate tab identifiers in the response.');
282+
}
283+
238284
$tabLookupDeferred->resolve($tabIdentifiers);
239285
} catch (Throwable $exception) {
240286
$reason = new RuntimeException(
@@ -281,6 +327,10 @@ public function getActiveTabIdentifier(string $sessionIdentifier): PromiseInterf
281327
function (ResponseInterface $response) {
282328
$tabIdentifier = $this->deserializeResponse($response);
283329

330+
if (!is_string($tabIdentifier)) {
331+
throw new RuntimeException('Unable to locate a tab identifier in the response.');
332+
}
333+
284334
return $tabIdentifier;
285335
}
286336
)
@@ -396,6 +446,10 @@ public function getCurrentUri(string $sessionIdentifier): PromiseInterface
396446
function (ResponseInterface $response) {
397447
$uriCurrent = $this->deserializeResponse($response);
398448

449+
if (!is_string($uriCurrent)) {
450+
throw new RuntimeException('Unable to locate an URI in the response.');
451+
}
452+
399453
return $uriCurrent;
400454
}
401455
)
@@ -433,6 +487,10 @@ public function getSource(string $sessionIdentifier): PromiseInterface
433487
function (ResponseInterface $response) {
434488
$sourceCode = $this->deserializeResponse($response);
435489

490+
if (!is_string($sourceCode)) {
491+
throw new RuntimeException('Unable to locate source code in the response.');
492+
}
493+
436494
return $sourceCode;
437495
}
438496
)
@@ -557,6 +615,10 @@ public function getElementVisibility(string $sessionIdentifier, array $elementId
557615
function (ResponseInterface $response) {
558616
$visibilityStatus = $this->deserializeResponse($response);
559617

618+
if (!is_bool($visibilityStatus)) {
619+
throw new RuntimeException('Unable to locate a visibility status in the response.');
620+
}
621+
560622
return $visibilityStatus;
561623
}
562624
)
@@ -736,7 +798,12 @@ public function getScreenshot(string $sessionIdentifier): PromiseInterface
736798
->then(
737799
function (ResponseInterface $response) {
738800
$imageContentsEncoded = $this->deserializeResponse($response);
739-
$imageContents = base64_decode($imageContentsEncoded);
801+
802+
if (!is_string($imageContentsEncoded)) {
803+
throw new RuntimeException('Unable to locate screenshot contents in the response.');
804+
}
805+
806+
$imageContents = base64_decode($imageContentsEncoded);
740807

741808
return $imageContents;
742809
}

src/SeleniumHubDriver.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,12 @@ public function createSession(): PromiseInterface
104104
*/
105105
public function getSessionIdentifiers(): PromiseInterface
106106
{
107-
// todo: implementation
107+
$identifierListPromise = $this->hubClient->getSessionIdentifiers();
108108

109-
return reject(new RuntimeException('Not implemented.'));
109+
return $this->timeoutInterceptor->applyTimeout(
110+
$identifierListPromise,
111+
'Unable to complete a get session identifiers command.'
112+
);
110113
}
111114

112115
/**
@@ -127,10 +130,10 @@ public function removeSession(string $sessionIdentifier): PromiseInterface
127130
*/
128131
public function getTabIdentifiers(string $sessionIdentifier): PromiseInterface
129132
{
130-
$sessionIdentifierPromise = $this->hubClient->getTabIdentifiers($sessionIdentifier);
133+
$tabIdentifierListPromise = $this->hubClient->getTabIdentifiers($sessionIdentifier);
131134

132135
return $this->timeoutInterceptor->applyTimeout(
133-
$sessionIdentifierPromise,
136+
$tabIdentifierListPromise,
134137
'Unable to complete a tab lookup command.'
135138
);
136139
}

0 commit comments

Comments
 (0)