Skip to content

Commit

Permalink
Upgrade phpstan; increase phpstan level; fix a few bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
uuf6429 committed Jan 1, 2025
1 parent 48e5773 commit 40df2cc
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 15 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
},
"require-dev": {
"mink/driver-testsuite": "dev-master",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan": "^2",
"phpstan/phpstan-phpunit": "^2",
"phpunit/phpunit": "^9.6.8",
"symfony/error-handler": "^5.4 || ^6.0 || ^7.0",
"symfony/process": "^5.4 || ^6.0 || ^7.0",
Expand Down
6 changes: 4 additions & 2 deletions phpstan.dist.neon
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
parameters:
level: 8
level: 10
paths:
- src
- tests
checkMissingIterableValueType: false
treatPhpDocTypesAsCertain: false
stubFiles:
- stubs/WebDriverTimeouts.stub
- stubs/RemoteWebDriver.stub

includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
Expand Down
42 changes: 35 additions & 7 deletions src/WebdriverClassicDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ class WebdriverClassicDriver extends CoreDriver

private DesiredCapabilities $desiredCapabilities;

/**
* @var array{script?: null|numeric, implicit?: null|numeric, page?: null|numeric}
*/
private array $timeouts = [];

private string $webDriverHost;
Expand All @@ -85,6 +88,7 @@ class WebdriverClassicDriver extends CoreDriver

/**
* @param string $browserName One of 'edge', 'firefox', 'chrome' or any one of {@see WebDriverBrowserType} constants.
* @param array<string, mixed> $desiredCapabilities
*/
public function __construct(
string $browserName = self::DEFAULT_BROWSER,
Expand Down Expand Up @@ -262,7 +266,7 @@ public function getWindowNames(): array

public function getWindowName(): string
{
$name = (string)$this->evaluateScript('window.name');
$name = $this->getAsString($this->evaluateScript('window.name'), 'Window name');

if ($name === '') {
$name = self::W3C_WINDOW_HANDLE_PREFIX . $this->getWebDriver()->getWindowHandle();
Expand Down Expand Up @@ -299,22 +303,22 @@ public function getText(
return trim(str_replace(
["\r\n", "\r", "\n", "\xc2\xa0"],
' ',
$this->getElementDomProperty($this->findElement($xpath), 'innerText')
$this->getAsString($this->getElementDomProperty($this->findElement($xpath), 'innerText'), 'The element\'s innerText')
));
}

public function getHtml(
#[Language('XPath')]
string $xpath
): string {
return $this->getElementDomProperty($this->findElement($xpath), 'innerHTML');
return $this->getAsString($this->getElementDomProperty($this->findElement($xpath), 'innerHTML'), 'The element\'s innerHTML');
}

public function getOuterHtml(
#[Language('XPath')]
string $xpath
): string {
return $this->getElementDomProperty($this->findElement($xpath), 'outerHTML');
return $this->getAsString($this->getElementDomProperty($this->findElement($xpath), 'outerHTML'), 'The element\'s outerHTML');
}

public function getAttribute(
Expand All @@ -326,9 +330,13 @@ public function getAttribute(
// so we cannot use webdriver api for this. See also: https://w3c.github.io/webdriver/#dfn-get-element-attribute
$escapedName = $this->jsonEncode($name, 'get attribute', 'attribute name');
$script = "return arguments[0].getAttribute($escapedName)";
return $this->executeJsOnXpath($xpath, $script);
$result = $this->executeJsOnXpath($xpath, $script);
return $result === null ? null : $this->getAsString($result, "The element's $name attribute");
}

/**
* @return array<array-key, mixed>|bool|mixed|string|null
*/
public function getValue(
#[Language('XPath')]
string $xpath
Expand Down Expand Up @@ -369,6 +377,9 @@ public function getValue(
}
}

/**
* @param array<array-key, mixed>|bool|mixed|string|null $value
*/
public function setValue(
#[Language('XPath')]
string $xpath,
Expand All @@ -386,7 +397,7 @@ public function setValue(
if (is_array($value)) {
$this->deselectAllOptions($element);
foreach ($value as $option) {
$this->selectOptionOnElement($element, $option, true);
$this->selectOptionOnElement($element, $this->getAsString($option, 'Option value'), true);
}
return;
}
Expand Down Expand Up @@ -736,7 +747,7 @@ public function getWebDriverSessionId(): ?string
/**
* Sets the timeouts to apply to the webdriver session
*
* @param array $timeouts The session timeout settings: Array of {script, implicit, page} => time in milliseconds
* @param array{script?: numeric, implicit?: numeric, page?: numeric} $timeouts The session timeout settings: Array of {script, implicit, page} => time in milliseconds
* @throws DriverException
* @api
*/
Expand Down Expand Up @@ -785,6 +796,8 @@ private function getNormalisedBrowserName(): string
/**
* Detect and assign appropriate browser capabilities
*
* @param array<string, mixed> $desiredCapabilities
*
* @see https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities
*/
private function initCapabilities(array $desiredCapabilities): DesiredCapabilities
Expand Down Expand Up @@ -1227,5 +1240,20 @@ private function getElementDomProperty(RemoteWebElement $element, string $proper
}
}

/**
* @param mixed $value
*/
private function getAsString($value, string $name): string
{
if (!is_scalar($value)) {
$actualType = gettype($value);
throw new \RuntimeException(
"$name should be a string or at least a scalar value, but received `$actualType` instead"
);

Check warning on line 1252 in src/WebdriverClassicDriver.php

View check run for this annotation

Codecov / codecov/patch

src/WebdriverClassicDriver.php#L1249-L1252

Added lines #L1249 - L1252 were not covered by tests
}

return (string)$value;
}

// </editor-fold>
}
11 changes: 11 additions & 0 deletions stubs/RemoteWebDriver.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Facebook\WebDriver\Remote;

interface RemoteWebDriver
{
/**
* @return list<string>
*/
public function getWindowHandles(): array;
}
24 changes: 24 additions & 0 deletions stubs/WebDriverTimeouts.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Facebook\WebDriver;

/**
* To be removed after {@see https://github.com/php-webdriver/php-webdriver/pull/1120} is merged.
*/
interface WebDriverTimeouts
{
/**
* @param null|int|float $seconds Wait time in seconds.
*/
public function implicitlyWait($seconds): self;

/**
* @param null|int|float $seconds Wait time in seconds.
*/
public function setScriptTimeout($seconds): self;

/**
* @param null|int|float $seconds Wait time in seconds.
*/
public function pageLoadTimeout($seconds): self;
}
3 changes: 3 additions & 0 deletions tests/Custom/TimeoutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public function testDeprecatedShortPageLoadTimeoutThrowsException(string $type):
$this->driver->visit($this->pathTo('/page_load.php?sleep=2'));
}

/**
* @return iterable<array{type: string}>
*/
public static function deprecatedPageLoadDataProvider(): iterable
{
yield 'selenium 3 style' => ['type' => 'pageLoad'];
Expand Down
5 changes: 4 additions & 1 deletion tests/WebdriverClassicConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ public static function getInstance(): self

public function createDriver(): WebdriverClassicDriver
{
$seleniumHost = $_SERVER['DRIVER_URL'];
$seleniumHost = $_SERVER['DRIVER_URL'] ?? null;
if (!is_string($seleniumHost)) {
throw new \RuntimeException('Selenium host must be specified (as a string) in $_SERVER[DRIVER_URL].');
}

return new WebdriverClassicDriver($this->getBrowserName(), [], $seleniumHost);
}
Expand Down
8 changes: 5 additions & 3 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

use Symfony\Component\Process\Process;

$minkTestServerPort = isset($_SERVER['WEB_FIXTURES_HOST'])
? parse_url($_SERVER['WEB_FIXTURES_HOST'], PHP_URL_PORT)
: '8002';
$fixturesHost = $_SERVER['WEB_FIXTURES_HOST'] ?? '//host:8002';
if (!is_string($fixturesHost)) {
throw new RuntimeException('The fixtures host must be specified in $_SERVER[WEB_FIXTURES_HOST] as a string');
}
$minkTestServerPort = parse_url($fixturesHost, PHP_URL_PORT);

$minkTestServer = new Process([
PHP_BINARY,
Expand Down

0 comments on commit 40df2cc

Please sign in to comment.