Skip to content

Commit

Permalink
Implement driver initializer (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
uuf6429 authored Jan 5, 2025
1 parent 5206bb4 commit 00b5f88
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 43 deletions.
25 changes: 20 additions & 5 deletions src/WebdriverClassicDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'];
}

// <editor-fold desc="Implementation">
Expand Down Expand Up @@ -751,7 +762,7 @@ public function setTimeouts(array $timeouts): void

// </editor-fold>

// <editor-fold desc="Private Utilities">
// <editor-fold desc="Extension Points">

/**
* @throws DriverException
Expand All @@ -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);
}

/**
Expand All @@ -777,9 +788,13 @@ protected function getWebDriver(): RemoteWebDriver
throw new DriverException('Base driver has not been created');
}

protected function getDesiredCapabilities(): array
// </editor-fold>

// <editor-fold desc="Private Utilities">

private static function instantiateWebDriver(string $driverHost, DesiredCapabilities $capabilities): RemoteWebDriver
{
return $this->desiredCapabilities->toArray();
return RemoteWebDriver::create($driverHost, $capabilities);
}

private function getNormalisedBrowserName(): string
Expand Down
42 changes: 18 additions & 24 deletions tests/Custom/CapabilityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, mixed> $desiredCapabilities
* @param array<string, mixed> $expectedCapabilities
Expand All @@ -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
Expand Down Expand Up @@ -78,26 +94,4 @@ public static function capabilitiesDataProvider(): iterable
],
];
}

/**
* @param string $browserName
* @param array<string, mixed> $desiredCapabilities
* @return WebdriverClassicDriver&object{capabilities: array<string, mixed>}
*/
private function createDriverExposingCapabilities(string $browserName, array $desiredCapabilities = []): WebdriverClassicDriver
{
return new class($browserName, $desiredCapabilities) extends WebdriverClassicDriver {
/**
* @var array<string, mixed>
*/
public array $capabilities;

public function __construct(string $browserName, array $desiredCapabilities)
{
parent::__construct($browserName, $desiredCapabilities);

$this->capabilities = $this->getDesiredCapabilities();
}
};
}
}
25 changes: 11 additions & 14 deletions tests/Custom/WebDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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');
Expand All @@ -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');
Expand Down
34 changes: 34 additions & 0 deletions tests/WebDriverMockingTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Mink\WebdriverClassicDriver\Tests;

use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverOptions;
use Facebook\WebDriver\WebDriverTimeouts;
use PHPUnit\Framework\MockObject\MockObject;

trait WebDriverMockingTrait
{
/**
* @template T
* @param class-string<T> $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;
}
}

0 comments on commit 00b5f88

Please sign in to comment.