Skip to content

Commit 5f77a78

Browse files
committed
Use itnerfaces as much as possible; switch to actions convenience class
1 parent 602aa24 commit 5f77a78

File tree

2 files changed

+78
-51
lines changed

2 files changed

+78
-51
lines changed

phpstan.dist.neon

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ parameters:
3232
count: 1
3333
path: src/WebdriverClassicDriver.php
3434
-
35-
message: '#^Parameter \#1 \$handle of method Facebook\\WebDriver\\Remote\\RemoteTargetLocator\:\:window\(\) expects string, mixed given\.$#'
35+
message: '#^Parameter \#1 \$handle of method Facebook\\WebDriver\\WebDriverTargetLocator\:\:window\(\) expects string, mixed given\.$#'
3636
identifier: argument.type
3737
count: 3
3838
path: src/WebdriverClassicDriver.php
39+
-
40+
# See https://github.com/php-webdriver/php-webdriver/blob/998e499b786805568deaf8cbf06f4044f05d91bf/lib/WebDriverElement.php#L43
41+
message: '#^Call to an undefined method Facebook\\WebDriver\\Internal\\WebDriverLocatable\&Facebook\\WebDriver\\WebDriverElement\:\:getDomProperty\(\)\.$#'
42+
identifier: method.notFound
43+
count: 1
44+
path: src/WebdriverClassicDriver.php

src/WebdriverClassicDriver.php

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@
1818
use Facebook\WebDriver\Exception\TimeoutException;
1919
use Facebook\WebDriver\Exception\UnsupportedOperationException;
2020
use Facebook\WebDriver\Exception\WebDriverException;
21+
use Facebook\WebDriver\Interactions\WebDriverActions;
22+
use Facebook\WebDriver\Internal\WebDriverLocatable;
23+
use Facebook\WebDriver\JavaScriptExecutor;
2124
use Facebook\WebDriver\Remote\DesiredCapabilities;
2225
use Facebook\WebDriver\Remote\RemoteWebDriver;
23-
use Facebook\WebDriver\Remote\RemoteWebElement;
2426
use Facebook\WebDriver\Remote\WebDriverBrowserType;
2527
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
28+
use Facebook\WebDriver\WebDriver;
2629
use Facebook\WebDriver\WebDriverBy;
2730
use Facebook\WebDriver\WebDriverDimension;
2831
use Facebook\WebDriver\WebDriverElement;
32+
use Facebook\WebDriver\WebDriverHasInputDevices;
2933
use Facebook\WebDriver\WebDriverPlatform;
3034
use Facebook\WebDriver\WebDriverRadios;
3135
use Facebook\WebDriver\WebDriverSelect;
@@ -35,7 +39,9 @@
3539
* @phpstan-type TTimeouts array{script?: null|numeric, implicit?: null|numeric, page?: null|numeric, "page load"?: null|numeric, pageLoad?: null|numeric}
3640
* @phpstan-type TCapabilities array<string, mixed>
3741
* @phpstan-type TElementValue array<array-key, mixed>|bool|mixed|string|null
38-
* @phpstan-type TWebDriverInstantiator callable(string $driverHost, DesiredCapabilities $capabilities): RemoteWebDriver
42+
* @phpstan-type TWebDriver WebDriver&JavaScriptExecutor&WebDriverHasInputDevices
43+
* @phpstan-type TWebDriverElement WebDriverElement&WebDriverLocatable
44+
* @phpstan-type TWebDriverInstantiator callable(string $driverHost, DesiredCapabilities $capabilities): TWebDriver
3945
*/
4046
class WebdriverClassicDriver extends CoreDriver
4147
{
@@ -77,7 +83,10 @@ class WebdriverClassicDriver extends CoreDriver
7783

7884
private const W3C_WINDOW_HANDLE_PREFIX = 'w3cwh:';
7985

80-
private ?RemoteWebDriver $webDriver = null;
86+
/**
87+
* @var TWebDriver|null
88+
*/
89+
private ?WebDriver $webDriver = null;
8190

8291
private string $browserName;
8392

@@ -210,7 +219,7 @@ public function switchToWindow(?string $name = null): void
210219
public function switchToIFrame(?string $name = null): void
211220
{
212221
$frameQuery = $name;
213-
if ($name && $this->getWebDriver()->isW3cCompliant()) {
222+
if ($name && $this->isW3cCompliant()) {
214223
try {
215224
$frameQuery = $this->getWebDriver()->findElement(WebDriverBy::id($name));
216225
} catch (NoSuchElementException $e) {
@@ -569,14 +578,18 @@ public function doubleClick(
569578
#[Language('XPath')]
570579
string $xpath
571580
): void {
572-
$this->doubleClickOnElement($this->findElement($xpath));
581+
$element = $this->findElement($xpath);
582+
$element->getLocationOnScreenOnceScrolledIntoView();
583+
$this->actions()->doubleClick($element)->perform();
573584
}
574585

575586
public function rightClick(
576587
#[Language('XPath')]
577588
string $xpath
578589
): void {
579-
$this->rightClickOnElement($this->findElement($xpath));
590+
$element = $this->findElement($xpath);
591+
$element->getLocationOnScreenOnceScrolledIntoView();
592+
$this->actions()->contextClick($element)->perform();
580593
}
581594

582595
public function attachFile(
@@ -601,7 +614,9 @@ public function mouseOver(
601614
#[Language('XPath')]
602615
string $xpath
603616
): void {
604-
$this->mouseOverElement($this->findElement($xpath));
617+
$element = $this->findElement($xpath);
618+
$element->getLocationOnScreenOnceScrolledIntoView();
619+
$this->actions()->moveToElement($element)->perform();
605620
}
606621

607622
public function focus(
@@ -656,7 +671,7 @@ public function dragTo(
656671
): void {
657672
$source = $this->findElement($sourceXpath);
658673
$destination = $this->findElement($destinationXpath);
659-
$this->getWebDriver()->action()->dragAndDrop($source, $destination)->perform();
674+
$this->actions()->dragAndDrop($source, $destination)->perform();
660675
}
661676

662677
public function executeScript(
@@ -751,8 +766,8 @@ public function getBrowserName(): string
751766
*/
752767
public function getWebDriverSessionId(): ?string
753768
{
754-
return $this->isStarted()
755-
? $this->getWebDriver()->getSessionID()
769+
return $this->isStarted() && method_exists($this->getWebDriver(), 'getSessionId')
770+
? $this->getAsString($this->getWebDriver()->getSessionID(), 'Session ID')
756771
: null;
757772
}
758773

@@ -789,15 +804,16 @@ protected function createWebDriver(): void
789804
}
790805

791806
/**
807+
* @return TWebDriver
792808
* @throws DriverException
793809
*/
794-
protected function getWebDriver(): RemoteWebDriver
810+
protected function getWebDriver(): WebDriver
795811
{
796-
if ($this->webDriver) {
797-
return $this->webDriver;
812+
if (!$this->webDriver) {
813+
throw new DriverException('Base driver has not been created');
798814
}
799815

800-
throw new DriverException('Base driver has not been created');
816+
return $this->webDriver;
801817
}
802818

803819
// </editor-fold>
@@ -886,6 +902,15 @@ private function createBrowserSpecificCapabilities(): DesiredCapabilities
886902
}
887903
}
888904

905+
/**
906+
* @throws DriverException
907+
*/
908+
private function actions(): WebDriverActions
909+
{
910+
// WebDriverActions are not reset after being performed - that's why we create a new instance each time.
911+
return new WebDriverActions($this->getWebDriver());
912+
}
913+
889914
/**
890915
* @throws DriverException
891916
*/
@@ -963,11 +988,12 @@ private function executeJsOnXpath(
963988
* $this->executeJsOnElement($element, 'return argument[0].childNodes.length');
964989
* ```
965990
*
991+
* @param TWebDriverElement $element
966992
* @return mixed
967993
* @throws DriverException
968994
*/
969995
private function executeJsOnElement(
970-
WebDriverElement $element,
996+
$element,
971997
#[Language('JavaScript')]
972998
string $script
973999
) {
@@ -1040,37 +1066,14 @@ private function getWindowHandleFromName(string $name): string
10401066
}
10411067
}
10421068

1043-
private function clickOnElement(WebDriverElement $element): void
1044-
{
1045-
$element->getLocationOnScreenOnceScrolledIntoView();
1046-
$element->click();
1047-
}
1048-
10491069
/**
1070+
* @param TWebDriverElement $element
10501071
* @throws DriverException
10511072
*/
1052-
private function doubleClickOnElement(RemoteWebElement $element): void
1073+
private function clickOnElement($element): void
10531074
{
10541075
$element->getLocationOnScreenOnceScrolledIntoView();
1055-
$this->getWebDriver()->getMouse()->doubleClick($element->getCoordinates());
1056-
}
1057-
1058-
/**
1059-
* @throws DriverException
1060-
*/
1061-
private function rightClickOnElement(RemoteWebElement $element): void
1062-
{
1063-
$element->getLocationOnScreenOnceScrolledIntoView();
1064-
$this->getWebDriver()->getMouse()->contextClick($element->getCoordinates());
1065-
}
1066-
1067-
/**
1068-
* @throws DriverException
1069-
*/
1070-
private function mouseOverElement(RemoteWebElement $element): void
1071-
{
1072-
$element->getLocationOnScreenOnceScrolledIntoView();
1073-
$this->getWebDriver()->getMouse()->mouseMove($element->getCoordinates());
1076+
$this->actions()->click($element)->perform();
10741077
}
10751078

10761079
/**
@@ -1100,24 +1103,28 @@ private function withWindow(?string $name, callable $callback): void
11001103
}
11011104

11021105
/**
1106+
* @return TWebDriverElement
11031107
* @throws DriverException
11041108
*/
11051109
private function findElement(
11061110
#[Language('XPath')]
11071111
string $xpath
1108-
): RemoteWebElement {
1112+
) {
11091113
try {
11101114
$finder = WebDriverBy::xpath($xpath);
1111-
return $this->getWebDriver()->findElement($finder);
1115+
$element = $this->getWebDriver()->findElement($finder);
1116+
assert($element instanceof WebDriverLocatable);
1117+
return $element;
11121118
} catch (\Throwable $e) {
11131119
throw new DriverException("Failed to find element: {$e->getMessage()}", 0, $e);
11141120
}
11151121
}
11161122

11171123
/**
1124+
* @param TWebDriverElement $element
11181125
* @throws DriverException
11191126
*/
1120-
private function selectRadioValue(WebDriverElement $element, string $value): void
1127+
private function selectRadioValue($element, string $value): void
11211128
{
11221129
try {
11231130
(new WebDriverRadios($element))->selectByValue($value);
@@ -1133,9 +1140,10 @@ private function selectRadioValue(WebDriverElement $element, string $value): voi
11331140
}
11341141

11351142
/**
1143+
* @param TWebDriverElement $element
11361144
* @throws DriverException
11371145
*/
1138-
private function selectOptionOnElement(WebDriverElement $element, string $value, bool $multiple = false): void
1146+
private function selectOptionOnElement($element, string $value, bool $multiple = false): void
11391147
{
11401148
try {
11411149
$select = new WebDriverSelect($element);
@@ -1163,9 +1171,10 @@ private function selectOptionOnElement(WebDriverElement $element, string $value,
11631171
*
11641172
* Note: this implementation does not trigger a change event after deselecting the elements.
11651173
*
1174+
* @param TWebDriverElement $element
11661175
* @throws DriverException
11671176
*/
1168-
private function deselectAllOptions(WebDriverElement $element): void
1177+
private function deselectAllOptions($element): void
11691178
{
11701179
try {
11711180
(new WebDriverSelect($element))->deselectAll();
@@ -1180,10 +1189,11 @@ private function deselectAllOptions(WebDriverElement $element): void
11801189
}
11811190

11821191
/**
1192+
* @param TWebDriverElement $element
11831193
* @throws DriverException
11841194
*/
11851195
private function ensureInputType(
1186-
WebDriverElement $element,
1196+
$element,
11871197
#[Language('XPath')]
11881198
string $xpath,
11891199
string $type,
@@ -1223,10 +1233,11 @@ private function jsonEncode($value, string $action, string $field): string
12231233
}
12241234

12251235
/**
1236+
* @param TWebDriverElement $element
12261237
* @param mixed $value
12271238
* @throws DriverException
12281239
*/
1229-
private function setElementDomProperty(WebDriverElement $element, string $property, $value): void
1240+
private function setElementDomProperty($element, string $property, $value): void
12301241
{
12311242
$this->executeJsOnElement(
12321243
$element,
@@ -1235,13 +1246,14 @@ private function setElementDomProperty(WebDriverElement $element, string $proper
12351246
}
12361247

12371248
/**
1249+
* @param TWebDriverElement $element
12381250
* @return mixed
12391251
* @throws DriverException
12401252
*/
1241-
private function getElementDomProperty(RemoteWebElement $element, string $property)
1253+
private function getElementDomProperty($element, string $property)
12421254
{
12431255
try {
1244-
return $this->getWebDriver()->isW3cCompliant()
1256+
return $this->isW3cCompliant()
12451257
? $element->getDomProperty($property)
12461258
: $this->executeJsOnElement($element, "return arguments[0]['$property']");
12471259
} catch (UnsupportedOperationException $e) {
@@ -1270,5 +1282,14 @@ private function getAsString($value, string $name): string
12701282
return (string)$value;
12711283
}
12721284

1285+
private function isW3cCompliant(): bool
1286+
{
1287+
if (!method_exists($this->getWebDriver(), 'isW3cCompliant')) {
1288+
throw new DriverException('Base driver must implement an `isW3cCompliant` method that returns a boolean.');
1289+
}
1290+
1291+
return (bool)$this->getWebDriver()->isW3cCompliant();
1292+
}
1293+
12731294
// </editor-fold>
12741295
}

0 commit comments

Comments
 (0)