Skip to content

Commit 6c20460

Browse files
committed
mouseMove() and mouseLeftClick() command implementations (W3C client)
1 parent 3d47c2c commit 6c20460

2 files changed

Lines changed: 145 additions & 14 deletions

File tree

src/Client/W3CClient.php

Lines changed: 129 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,7 @@ public function openUri(string $sessionIdentifier, string $uri): PromiseInterfac
287287
$navigationPromise = $responsePromise
288288
->then(
289289
function (ResponseInterface $response) {
290-
$responseBody = (string) $response->getBody();
291-
292-
// todo: locate an error message or set it as "undefined error"
293-
if ('{"value":null}' !== $responseBody) {
294-
throw new RuntimeException('URI navigation is not confirmed.');
295-
}
290+
$this->onCommandConfirmation($response, 'URI navigation is not confirmed.');
296291

297292
return null;
298293
}
@@ -432,19 +427,78 @@ public function mouseMove(
432427
int $moveDuration = 100,
433428
array $startingPoint = null
434429
): PromiseInterface {
435-
// TODO: Implement mouseMove() method.
430+
if (is_array($startingPoint)) {
431+
$actionOrigin = $startingPoint;
432+
} else {
433+
$actionOrigin = 'pointer';
434+
}
435+
436+
$mouseActions = [
437+
[
438+
'type' => 'pointerMove',
439+
'origin' => $actionOrigin,
440+
'x' => $offsetX,
441+
'y' => $offsetY,
442+
'duration' => $moveDuration,
443+
],
444+
];
436445

437-
return reject(new RuntimeException('Not implemented.'));
446+
$responsePromise = $this->requestMouseActions($sessionIdentifier, $mouseActions);
447+
448+
$moveConfirmationPromise = $responsePromise
449+
->then(
450+
function (ResponseInterface $response) {
451+
$this->onCommandConfirmation($response, 'Mouse move command is not confirmed.');
452+
453+
return null;
454+
}
455+
)
456+
->then(
457+
null,
458+
function (Throwable $rejectionReason) {
459+
throw new RuntimeException('Unable to confirm mouse move action (request).', 0, $rejectionReason);
460+
}
461+
)
462+
;
463+
464+
return $moveConfirmationPromise;
438465
}
439466

440467
/**
441468
* {@inheritDoc}
442469
*/
443470
public function mouseLeftClick(string $sessionIdentifier): PromiseInterface
444471
{
445-
// TODO: Implement mouseLeftClick() method.
472+
$mouseActions = [
473+
[
474+
'type' => 'pointerDown',
475+
'button' => 0,
476+
],
477+
[
478+
'type' => 'pointerUp',
479+
'button' => 0,
480+
],
481+
];
446482

447-
return reject(new RuntimeException('Not implemented.'));
483+
$responsePromise = $this->requestMouseActions($sessionIdentifier, $mouseActions);
484+
485+
$clickConfirmationPromise = $responsePromise
486+
->then(
487+
function (ResponseInterface $response) {
488+
$this->onCommandConfirmation($response, 'Mouse click command is not confirmed.');
489+
490+
return null;
491+
}
492+
)
493+
->then(
494+
null,
495+
function (Throwable $rejectionReason) {
496+
throw new RuntimeException('Unable to confirm mouse click action (request).', 0, $rejectionReason);
497+
}
498+
)
499+
;
500+
501+
return $clickConfirmationPromise;
448502
}
449503

450504
/**
@@ -456,4 +510,69 @@ public function getScreenshot(string $sessionIdentifier): PromiseInterface
456510

457511
return reject(new RuntimeException('Not implemented.'));
458512
}
513+
514+
/**
515+
* Initializes a request to execute a sequence of mouse-specific actions in the remote browser
516+
*
517+
* @param string $sessionIdentifier Session identifier for Selenium Grid server (hub)
518+
* @param array $mouseActions A data structure that describes a sequence of actions to be performed by the
519+
* internal pointer with type "mouse"
520+
*
521+
* @return PromiseInterface<ResponseInterface>
522+
*/
523+
private function requestMouseActions(string $sessionIdentifier, array $mouseActions): PromiseInterface
524+
{
525+
$requestUri = sprintf(
526+
'http://%s:%d/wd/hub/session/%s/actions',
527+
$this->_options['server']['host'],
528+
$this->_options['server']['port'],
529+
$sessionIdentifier
530+
);
531+
532+
$requestHeaders = [
533+
'Content-Type' => 'application/json; charset=UTF-8',
534+
];
535+
536+
$requestContents = json_encode(
537+
[
538+
'actions' => [
539+
[
540+
'type' => 'pointer',
541+
'id' => 'mouse',
542+
'parameters' => [
543+
'pointerType' => 'mouse',
544+
],
545+
'actions' => $mouseActions,
546+
],
547+
],
548+
]
549+
);
550+
551+
$responsePromise = $this->httpClient->post($requestUri, $requestHeaders, $requestContents);
552+
553+
return $responsePromise;
554+
}
555+
556+
/**
557+
* Ensures that a related action is properly executed (confirmed) by the remote server, triggers an error otherwise.
558+
*
559+
* Is used when no specific context to check is required (some methods will use more advanced confirmation checks
560+
* instead this "default").
561+
*
562+
* @param ResponseInterface $response PSR-7 response message from the Selenium hub with action results
563+
* @param string $errorMessage Will be used if an error is registered during confirmation check
564+
*
565+
* @return void
566+
*
567+
* @throws RuntimeException Whenever an error has occurred during confirmation check for a remote action
568+
*/
569+
private function onCommandConfirmation(ResponseInterface $response, string $errorMessage): void
570+
{
571+
$responseBody = (string) $response->getBody();
572+
573+
// todo: locate an error message or set it as "undefined error"
574+
if ('{"value":null}' !== $responseBody) {
575+
throw new RuntimeException($errorMessage);
576+
}
577+
}
459578
}

src/SeleniumHubDriver.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,19 +264,31 @@ public function mouseMove(
264264
int $moveDuration = 100,
265265
array $startingPoint = null
266266
): PromiseInterface {
267-
// TODO: Implement mouseMove() method.
267+
$moveConfirmationPromise = $this->hubClient->mouseMove(
268+
$sessionIdentifier,
269+
$offsetX,
270+
$offsetY,
271+
$moveDuration,
272+
$startingPoint
273+
);
268274

269-
return reject(new RuntimeException('Not implemented.'));
275+
return $this->timeoutInterceptor->applyTimeout(
276+
$moveConfirmationPromise,
277+
'Unable to complete a mouse move command.'
278+
);
270279
}
271280

272281
/**
273282
* {@inheritDoc}
274283
*/
275284
public function mouseLeftClick(string $sessionIdentifier): PromiseInterface
276285
{
277-
// TODO: Implement mouseLeftClick() method.
286+
$clickConfirmationPromise = $this->hubClient->mouseLeftClick($sessionIdentifier);
278287

279-
return reject(new RuntimeException('Not implemented.'));
288+
return $this->timeoutInterceptor->applyTimeout(
289+
$clickConfirmationPromise,
290+
'Unable to complete a mouse click command.'
291+
);
280292
}
281293

282294
/**

0 commit comments

Comments
 (0)