Skip to content

Commit 323404c

Browse files
committed
Merge branch '0.x' into 'master'
2 parents 4f4f347 + 1bc9ccc commit 323404c

File tree

7 files changed

+114
-23
lines changed

7 files changed

+114
-23
lines changed

CHANGELOG.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
# Changelog
23

34
All notable changes to this project will be documented in this file.
@@ -6,18 +7,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
67
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
78

89
## [Unreleased]
10+
911
### Changed
1012

1113
- No description yet.
1214

15+
## [0.3.0] - 2021-02-11
16+
17+
### Added
18+
19+
- `ClientInterface::removeSession()` implementation to properly close a WebDriver session.
20+
- Configurable `checkInterval` for the `WebDriverInterface::waitUntil()` method, to define a custom frequency for the
21+
condition checks.
22+
- README: minimal configuration snippet.
23+
24+
### Fixed
25+
26+
- `command.timeout` option now accepts both float and int values (will be normalized to float by the driver factory).
27+
- `onCommandConfirmation` hook is now propagates driver error message from the response alongside the predefined error
28+
label.
29+
1330
## [0.2.1] - 2020-12-22
31+
1432
### Fixed
1533

1634
- `WebDriverInterface::waitUntil()`: a resulting value from the promise, that has been generated by the
1735
"condition-to-satisfy" callback, is now properly forwarded to the `onFulfilled` handler, for the `waitUntil` method
1836
itself.
1937

2038
## [0.2.0] - 2020-12-18
39+
2140
### Added
2241

2342
- `ClientInterface::getTabIdentifiers()` method implementation (reading a list of tabs, which are opened in the
@@ -41,9 +60,11 @@ a screen state of the remote browser instance.
4160
- README: a "Requirements" block, description improvements.
4261

4362
### Changed
63+
4464
- `Timeout\Interceptor` is now raising a single exception with both method-specific message and a timeout context.
4565

4666
### Fixed
67+
4768
- Interface fixes and a minor redesign for some signatures.
4869

4970
This version brings an async variant for most methods (no tests yet), which were defined by the
@@ -69,6 +90,7 @@ for the executable file and profile preferences) to launch a browser instance (w
6990
```
7091

7192
## [0.1.0] (core design) - 2020-12-02
93+
7294
### Added
7395

7496
- `WebDriverInterface` and low-level `ClientInterface` to communicate with
@@ -84,7 +106,8 @@ browser instance).
84106
This early development version doesn't yet contain full implementation for the introduced `WebDriverInterface`, only
85107
core design solutions and library interfaces are defined.
86108

87-
[Unreleased]: https://github.com/itnelo/reactphp-webdriver/compare/0.2.1...0.x
109+
[Unreleased]: https://github.com/itnelo/reactphp-webdriver/compare/0.3.0...0.x
110+
[0.3.0]: https://github.com/itnelo/reactphp-webdriver/compare/0.2.1..0.3.0
88111
[0.2.1]: https://github.com/itnelo/reactphp-webdriver/compare/0.2.0..0.2.1
89112
[0.2.0]: https://github.com/itnelo/reactphp-webdriver/compare/0.1.0..0.2.0
90113
[0.1.0]: https://github.com/itnelo/reactphp-webdriver/releases/tag/0.1.0

README.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,27 @@ $ composer require itnelo/reactphp-webdriver:^0.2
3232

3333
## How to use
3434

35-
Call a factory method to get your instance (recommended):
35+
Call a factory method to get your instance (recommended). The minimal configuration is:
36+
37+
```php
38+
use React\EventLoop\Factory as LoopFactory;
39+
use Itnelo\React\WebDriver\WebDriverFactory;
40+
41+
$loop = LoopFactory::create();
42+
43+
$webDriver = WebDriverFactory::create(
44+
$loop,
45+
[
46+
'hub' => [
47+
'host' => 'selenium-hub',
48+
'port' => 4444,
49+
],
50+
]
51+
);
52+
```
53+
54+
You can customize a set of parameters for the underlying [ReactPHP Browser](https://github.com/reactphp/http#browser)
55+
and tune driver options:
3656

3757
```php
3858
use React\EventLoop\Factory as LoopFactory;
@@ -45,7 +65,7 @@ $webDriver = WebDriverFactory::create(
4565
[
4666
'browser' => [
4767
'tcp' => [
48-
'bindto' => '192.168.56.10:0',
68+
'bindto' => '192.169.56.10:0',
4969
],
5070
'tls' => [
5171
'verify_peer' => false,
@@ -63,7 +83,7 @@ $webDriver = WebDriverFactory::create(
6383
);
6484
```
6585

66-
Manual configuration (if you want to configure each component as a separate service, e.g. compiling a DI container
86+
Manual configuration (if you prefer to configure each component as a separate service, e.g. compiling a DI container
6787
and want to reuse existing service definitions):
6888

6989
```php
@@ -80,7 +100,7 @@ $socketConnector = new SocketConnector(
80100
$loop,
81101
[
82102
'tcp' => [
83-
'bindto' => '192.168.56.10:0',
103+
'bindto' => '192.169.56.10:0',
84104
],
85105
'tls' => [
86106
'verify_peer' => false,

src/Client/W3CClient.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/*
44
* This file is part of the ReactPHP WebDriver <https://github.com/itnelo/reactphp-webdriver>.
55
*
6-
* (c) 2020 Pavel Petrov <[email protected]>.
6+
* (c) 2020-2021 Pavel Petrov <[email protected]>.
77
*
88
* For the full copyright and license information, please view the LICENSE
99
* file that was distributed with this source code.
@@ -184,9 +184,30 @@ function (Throwable $rejectionReason) use ($sessionOpeningDeferred) {
184184
*/
185185
public function removeSession(string $sessionIdentifier): PromiseInterface
186186
{
187-
// todo: implementation
187+
$requestUri = sprintf(
188+
'http://%s:%d/wd/hub/session/%s',
189+
$this->_options['server']['host'],
190+
$this->_options['server']['port'],
191+
$sessionIdentifier
192+
);
188193

189-
return reject(new RuntimeException('Not implemented.'));
194+
$requestHeaders = [
195+
'Content-Type' => 'application/json; charset=UTF-8',
196+
];
197+
198+
$responsePromise = $this->httpClient->delete($requestUri, $requestHeaders);
199+
200+
$quitConfirmationPromise = $responsePromise
201+
->then(fn (ResponseInterface $response) => $this->onCommandConfirmation($response))
202+
->then(
203+
null,
204+
function (Throwable $rejectionReason) {
205+
throw new RuntimeException('Unable to close a session.', 0, $rejectionReason);
206+
}
207+
)
208+
;
209+
210+
return $quitConfirmationPromise;
190211
}
191212

192213
/**
@@ -817,10 +838,14 @@ private function onCommandConfirmation(ResponseInterface $response, string $erro
817838
{
818839
$responseValueNode = $this->deserializeResponse($response);
819840

820-
// todo: locate an error message or set it as "undefined error"
821-
if (null !== $responseValueNode) {
822-
throw new RuntimeException($errorMessage);
841+
if (null === $responseValueNode) {
842+
return;
823843
}
844+
845+
$driverMessage = $responseValueNode['message'] ?? 'undefined driver error';
846+
$confirmationErrorMessage = sprintf('%s %s.', $errorMessage, $driverMessage);
847+
848+
throw new RuntimeException($confirmationErrorMessage);
824849
}
825850

826851
/**

src/Routine/Condition/CheckRoutine.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function __construct(LoopInterface $loop, TimeoutInterceptor $timeoutInte
8484
*
8585
* @throws RuntimeException Whenever the routine is already in the running state
8686
*/
87-
public function run(callable $conditionMetCallback, float $checkInterval = 0.5): PromiseInterface
87+
public function run(callable $conditionMetCallback, float $checkInterval): PromiseInterface
8888
{
8989
if ($this->_evaluationTimer instanceof TimerInterface) {
9090
throw new RuntimeException('Routine is already running.');

src/SeleniumHubDriver.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/*
44
* This file is part of the ReactPHP WebDriver <https://github.com/itnelo/reactphp-webdriver>.
55
*
6-
* (c) 2020 Pavel Petrov <[email protected]>.
6+
* (c) 2020-2021 Pavel Petrov <[email protected]>.
77
*
88
* For the full copyright and license information, please view the LICENSE
99
* file that was distributed with this source code.
@@ -114,9 +114,12 @@ public function getSessionIdentifiers(): PromiseInterface
114114
*/
115115
public function removeSession(string $sessionIdentifier): PromiseInterface
116116
{
117-
// todo: implementation
117+
$quitConfirmationPromise = $this->hubClient->removeSession($sessionIdentifier);
118118

119-
return reject(new RuntimeException('Not implemented.'));
119+
return $this->timeoutInterceptor->applyTimeout(
120+
$quitConfirmationPromise,
121+
'Unable to complete a session remove command.'
122+
);
120123
}
121124

122125
/**
@@ -310,15 +313,21 @@ public function wait(float $time = 30.0): PromiseInterface
310313
/**
311314
* {@inheritDoc}
312315
*/
313-
public function waitUntil(callable $conditionMetCallback, float $time = 30.0): PromiseInterface
314-
{
315-
$timeNormalized = max(0.5, $time);
316+
public function waitUntil(
317+
callable $conditionMetCallback,
318+
float $time = 30.0,
319+
float $checkInterval = 0.5
320+
): PromiseInterface {
321+
$timeNormalized = max(0.5, $time);
322+
$checkIntervalNormalized = max(0.1, $checkInterval);
316323

317324
// todo: probably, should be redesigned, to reduce amount of "new" calls
318325
$timeoutInterceptor = new TimeoutInterceptor($this->loop, $timeNormalized);
319326
$checkRoutine = new ConditionCheckRoutine($this->loop, $timeoutInterceptor);
320327

321-
return $checkRoutine->run($conditionMetCallback);
328+
$conditionMetPromise = $checkRoutine->run($conditionMetCallback, $checkIntervalNormalized);
329+
330+
return $conditionMetPromise;
322331
}
323332

324333
/**

src/WebDriverFactory.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use React\Http\Browser;
2222
use React\Socket\Connector as SocketConnector;
2323
use Symfony\Component\OptionsResolver\Exception\ExceptionInterface as ConfigurationExceptionInterface;
24+
use Symfony\Component\OptionsResolver\Options;
2425
use Symfony\Component\OptionsResolver\OptionsResolver;
2526

2627
/**
@@ -41,7 +42,7 @@ final class WebDriverFactory
4142
* [
4243
* 'browser' => [
4344
* 'tcp' => [
44-
* 'bindto' => '192.168.56.10:0',
45+
* 'bindto' => '192.169.56.10:0',
4546
* ],
4647
* 'tls' => [
4748
* 'verify_peer' => false,
@@ -108,8 +109,16 @@ function (OptionsResolver $commandOptionsResolver) {
108109
'Maximum time to wait (in seconds) for command execution '
109110
. '(do not correlate with HTTP timeouts)'
110111
)
111-
->allowedTypes('float')
112+
->allowedTypes('int', 'float')
112113
->default(30.0)
114+
->normalize(
115+
function (Options $options, $commandTimeout) {
116+
$commandTimeoutNormalized = (float) $commandTimeout;
117+
$commandTimeoutNormalized = max(0.1, $commandTimeoutNormalized);
118+
119+
return $commandTimeoutNormalized;
120+
}
121+
)
113122
;
114123
}
115124
)

src/WebDriverInterface.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/*
44
* This file is part of the ReactPHP WebDriver <https://github.com/itnelo/reactphp-webdriver>.
55
*
6-
* (c) 2020 Pavel Petrov <[email protected]>.
6+
* (c) 2020-2021 Pavel Petrov <[email protected]>.
77
*
88
* For the full copyright and license information, please view the LICENSE
99
* file that was distributed with this source code.
@@ -116,10 +116,15 @@ public function wait(float $time = 30.0): PromiseInterface;
116116
* @param callable $conditionMetCallback A condition to be met, as a callback
117117
* @param float $time Time (in seconds) to wait for successfully resolved promise from the
118118
* condition callback (minimum: 0.5)
119+
* @param float $checkInterval The interval for condition checks, in seconds (minimum: 0.1)
119120
*
120121
* @return PromiseInterface<mixed>
121122
*/
122-
public function waitUntil(callable $conditionMetCallback, float $time = 30.0): PromiseInterface;
123+
public function waitUntil(
124+
callable $conditionMetCallback,
125+
float $time = 30.0,
126+
float $checkInterval = 0.5
127+
): PromiseInterface;
123128

124129
/**
125130
* Returns a promise that will be resolved if a screenshot is successfully received and saved using the specified

0 commit comments

Comments
 (0)