diff --git a/src/WebdriverClassicDriver.php b/src/WebdriverClassicDriver.php index d072288..97976be 100644 --- a/src/WebdriverClassicDriver.php +++ b/src/WebdriverClassicDriver.php @@ -31,6 +31,9 @@ use Facebook\WebDriver\WebDriverSelect; use JetBrains\PhpStorm\Language; +/** + * @phpstan-type TWebDriverInstantiator callable(string $driverHost, DesiredCapabilities $capabilities): RemoteWebDriver + */ class WebdriverClassicDriver extends CoreDriver { public const DEFAULT_BROWSER = WebDriverBrowserType::CHROME; @@ -81,19 +84,27 @@ class WebdriverClassicDriver extends CoreDriver private string $webDriverHost; + /** + * @var TWebDriverInstantiator + */ + private $webDriverInstantiator; + private ?string $initialWindowHandle = null; /** * @param string $browserName One of 'edge', 'firefox', 'chrome' or any one of {@see WebDriverBrowserType} constants. + * @param TWebDriverInstantiator|null $webDriverInstantiator */ public function __construct( string $browserName = self::DEFAULT_BROWSER, array $desiredCapabilities = [], - string $webDriverHost = 'http://localhost:4444/wd/hub' + string $webDriverHost = 'http://localhost:4444/wd/hub', + ?callable $webDriverInstantiator = null ) { $this->browserName = $browserName; $this->desiredCapabilities = $this->initCapabilities($desiredCapabilities); $this->webDriverHost = $webDriverHost; + $this->webDriverInstantiator = $webDriverInstantiator ?? [self::class, 'instantiateWebDriver']; } // @@ -751,7 +762,7 @@ public function setTimeouts(array $timeouts): void // - // + // /** * @throws DriverException @@ -762,7 +773,7 @@ protected function createWebDriver(): void throw new DriverException('Base driver has already been created'); } - $this->webDriver = RemoteWebDriver::create($this->webDriverHost, $this->getDesiredCapabilities()); + $this->webDriver = ($this->webDriverInstantiator)($this->webDriverHost, $this->desiredCapabilities); } /** @@ -777,9 +788,13 @@ protected function getWebDriver(): RemoteWebDriver throw new DriverException('Base driver has not been created'); } - protected function getDesiredCapabilities(): array + // + + // + + private static function instantiateWebDriver(string $driverHost, DesiredCapabilities $capabilities): RemoteWebDriver { - return $this->desiredCapabilities->toArray(); + return RemoteWebDriver::create($driverHost, $capabilities); } private function getNormalisedBrowserName(): string diff --git a/tests/Custom/CapabilityTest.php b/tests/Custom/CapabilityTest.php index f3a3082..9abc275 100644 --- a/tests/Custom/CapabilityTest.php +++ b/tests/Custom/CapabilityTest.php @@ -2,10 +2,13 @@ namespace Mink\WebdriverClassicDriver\Tests\Custom; +use Mink\WebdriverClassicDriver\Tests\WebDriverMockingTrait; use Mink\WebdriverClassicDriver\WebdriverClassicDriver; class CapabilityTest extends \PHPUnit\Framework\TestCase { + use WebDriverMockingTrait; + /** * @param array $desiredCapabilities * @param array $expectedCapabilities @@ -14,9 +17,22 @@ class CapabilityTest extends \PHPUnit\Framework\TestCase */ public function testThatCapabilitiesAreAsExpected(string $browserName, array $desiredCapabilities, array $expectedCapabilities): void { - $driver = $this->createDriverExposingCapabilities($browserName, $desiredCapabilities); + $mockWebDriver = $this->createMockWebDriver(); + + $actualCapabilities = null; + $driver = new WebdriverClassicDriver( + $browserName, + $desiredCapabilities, + 'example.com', + function ($host, $capabilities) use (&$actualCapabilities, $mockWebDriver) { + $actualCapabilities = $capabilities->toArray(); + return $mockWebDriver; + } + ); + + $driver->start(); - $this->assertSame($expectedCapabilities, $driver->capabilities); + $this->assertSame($expectedCapabilities, $actualCapabilities); } public static function capabilitiesDataProvider(): iterable @@ -78,26 +94,4 @@ public static function capabilitiesDataProvider(): iterable ], ]; } - - /** - * @param string $browserName - * @param array $desiredCapabilities - * @return WebdriverClassicDriver&object{capabilities: array} - */ - private function createDriverExposingCapabilities(string $browserName, array $desiredCapabilities = []): WebdriverClassicDriver - { - return new class($browserName, $desiredCapabilities) extends WebdriverClassicDriver { - /** - * @var array - */ - public array $capabilities; - - public function __construct(string $browserName, array $desiredCapabilities) - { - parent::__construct($browserName, $desiredCapabilities); - - $this->capabilities = $this->getDesiredCapabilities(); - } - }; - } } diff --git a/tests/Custom/WebDriverTest.php b/tests/Custom/WebDriverTest.php index 1c4ff40..6a778d4 100644 --- a/tests/Custom/WebDriverTest.php +++ b/tests/Custom/WebDriverTest.php @@ -3,10 +3,13 @@ namespace Mink\WebdriverClassicDriver\Tests\Custom; use Behat\Mink\Exception\DriverException; +use Mink\WebdriverClassicDriver\Tests\WebDriverMockingTrait; use Mink\WebdriverClassicDriver\WebdriverClassicDriver; class WebDriverTest extends TestCase { + use WebDriverMockingTrait; + public function testDriverMustBeStartedBeforeUse(): void { $this->expectException(DriverException::class); @@ -35,11 +38,9 @@ public function testStartedDriverCannotBeSubsequentlyStarted(): void public function testDriverCatchesUpstreamErrorsDuringStart(): void { - $driver = $this->createPartialMock(WebdriverClassicDriver::class, ['createWebDriver', 'getWebDriver']); - $driver - ->expects($this->once()) - ->method('createWebDriver') - ->willThrowException(new \RuntimeException('An upstream error')); + $driver = new WebdriverClassicDriver('fake browser', [], 'example.com', function () { + throw new \RuntimeException('An upstream error'); + }); $this->expectException(DriverException::class); $this->expectExceptionMessage('Could not start driver: An upstream error'); @@ -49,15 +50,11 @@ public function testDriverCatchesUpstreamErrorsDuringStart(): void public function testDriverCatchesUpstreamErrorsDuringStop(): void { - $driver = $this->createPartialMock(WebdriverClassicDriver::class, ['createWebDriver', 'isStarted', 'getWebDriver']); - $driver - ->expects($this->once()) - ->method('isStarted') - ->willReturn(true); - $driver - ->expects($this->once()) - ->method('getWebDriver') - ->willThrowException(new \RuntimeException('An upstream error')); + $mockWebDriver = $this->createMockWebDriver(); + $mockWebDriver->method('quit')->willThrowException(new \RuntimeException('An upstream error')); + $driver = new WebdriverClassicDriver('fake browser', [], 'example.com', fn() => $mockWebDriver); + + $driver->start(); $this->expectException(DriverException::class); $this->expectExceptionMessage('Could not close connection: An upstream error'); diff --git a/tests/WebDriverMockingTrait.php b/tests/WebDriverMockingTrait.php new file mode 100644 index 0000000..3bce02e --- /dev/null +++ b/tests/WebDriverMockingTrait.php @@ -0,0 +1,34 @@ + $class + * @return T&MockObject + */ + abstract function createMock(string $class): object; + + /** + * @return RemoteWebDriver&MockObject + */ + private function createMockWebDriver(): RemoteWebDriver + { + $mockWebDriverTimeouts = $this->createMock(WebDriverTimeouts::class); + + $mockWebDriverOptions = $this->createMock(WebDriverOptions::class); + $mockWebDriverOptions->method('timeouts')->willReturn($mockWebDriverTimeouts); + + $mockWebDriver = $this->createMock(RemoteWebDriver::class); + $mockWebDriver->method('manage')->willReturn($mockWebDriverOptions); + + return $mockWebDriver; + } +}