From 29842f557c35fa391c1e8b46fa61faeef5f344ba Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 23 Dec 2020 08:53:42 -0500 Subject: [PATCH] [BC BREAK] refactor test traits into just one: HasBrowser --- README.md | 251 ++++++++++------------- src/Browser.php | 14 ++ src/Browser/Extension/ContainerAware.php | 27 --- src/Browser/HttpBrowser.php | 20 +- src/Browser/Test/HasBrowser.php | 157 ++++++++++++-- src/Browser/Test/HasHttpBrowser.php | 72 ------- src/Browser/Test/HasKernelBrowser.php | 50 ----- src/Browser/Test/HasPantherBrowser.php | 62 ------ tests/BrowserTests.php | 15 +- tests/ConfigureBrowserTest.php | 14 +- tests/HttpBrowserTest.php | 7 +- tests/KernelBrowserTests.php | 7 +- tests/NonPantherHttpBrowserTest.php | 25 ++- tests/PantherBrowserTest.php | 7 +- 14 files changed, 309 insertions(+), 419 deletions(-) delete mode 100644 src/Browser/Extension/ContainerAware.php delete mode 100644 src/Browser/Test/HasHttpBrowser.php delete mode 100644 src/Browser/Test/HasKernelBrowser.php delete mode 100644 src/Browser/Test/HasPantherBrowser.php diff --git a/README.md b/README.md index 596fa8f..8091bd6 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ public function testViewPostAndAddComment() { // assumes a "Post" is in the database with an id of 3 - $this->browser() + $this->kernelBrowser() ->visit('/posts/3') ->assertSuccessful() ->assertSeeIn('title', 'My First Post') @@ -34,7 +34,7 @@ public function testViewPostAndAddComment() { $post = PostFactory::new()->create(['title' => 'My First Post']); - $this->browser() + $this->kernelBrowser() ->visit("/posts/{$post->getId()}") ->assertSuccessful() ->assertSeeIn('title', 'My First Post') @@ -76,8 +76,9 @@ There are several environment variables available to configure: | `BROWSER_SCREENSHOT_DIR` | Directory to save screenshots to. | `/var/browser/screenshots` | | `BROWSER_CONSOLE_LOG_DIR` | Directory to save javascript console logs to. | `/var/browser/console-logs` | | `KERNEL_BROWSER_CLASS` | `KernelBrowser` class to use. | `Zenstruck\Browser\KernelBrowser` | -| `HTTP_BROWSER_CLASS` | `HttpBrowser` class to use. | Zenstruck\Browser\HttpBrowser` | +| `HTTP_BROWSER_CLASS` | `HttpBrowser` class to use. | `Zenstruck\Browser\HttpBrowser` | | `PANTHER_BROWSER_CLASS` | `PantherBrowser` class to use. | `Zenstruck\Browser\PantherBrowser` | +| `HTTP_BROWSER_URI` | The URI to use for `HttpBrowser` (if not using `PantherTestCase`). | `null` | | `PANTHER_NO_HEADLESS` | Disable headless-mode and allow usage of `PantherBrowser::inspect()`. | `0` | @@ -90,6 +91,55 @@ This library provides 3 different "browsers": 3. [PantherBrowser](#pantherbrowser): makes requests to a webserver with a real browser using `symfony/panther` which allows testing javascript *(this is the slowest browser)*. +You can use these Browsers in your tests by having your test class use the `HasBrowser` trait: + +```php +namespace App\Tests; + +use PHPUnit\Framework\TestCase; +use Zenstruck\Browser\Test\HasBrowser; + +class MyTest extends TestCase +{ + use HasBrowser; + + /** + * Requires this test extend either Symfony\Bundle\FrameworkBundle\Test\KernelTestCase + * or Symfony\Bundle\FrameworkBundle\Test\WebTestCase. + */ + public function test_using_kernel_browser(): void + { + $this->kernelBrowser() + ->visit('/my/page') + ->assertSuccessful() + ; + } + + /** + * Requires this test extend Symfony\Component\Panther\PantherTestCase. + */ + public function test_using_panther_browser(): void + { + $this->pantherBrowser() + ->visit('/my/page') + ->assertSuccessful() + ; + } + + /** + * Requires this test extend Symfony\Component\Panther\PantherTestCase or + * have the "HTTP_BROWSER_URI" env var set to the root uri to test against. + */ + public function test_using_http_browser(): void + { + $this->httpBrowser() + ->visit('/my/page') + ->assertSuccessful() + ; + } +} +``` + All browsers have the following methods: ```php @@ -278,30 +328,7 @@ $browser ### KernelBrowser -This browser is a wrapper for `Symfony\Bundle\FrameworkBundle\KernelBrowser`. To use in your functional -tests, have your standard Symfony `WebTestCase` or `KernelTestCase` use the `HasKernelBrowser` trait: - -```php -namespace App\Tests; - -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Zenstruck\Browser\Test\HasKernelBrowser; - -class MyTest extends KernelTestCase -{ - use HasKernelBrowser; - - public function testDemo(): void - { - $this->browser() - ->visit('/my/page') - ->assertSuccessful() - ; - } -} -``` - -#### KernelBrowser Specific Methods +This browser has the following extra methods: ```php /** @var \Zenstruck\Browser\KernelBrowser $browser **/ @@ -326,67 +353,13 @@ $browser ### HttpBrowser -This browser is a wrapper for `Symfony\Component\BrowserKit\HttpBrowser` (requires `symfony/http-client`). -To use in your functional tests, have your test use the `HasHttpBrowser` and override the -`httpBrowserBaseUri()` method: - -```php -namespace App\Tests; - -use PHPUnit\Framework\TestCase; -use Zenstruck\Browser\Test\HasHttpBrowser; - -class MyTest extends TestCase -{ - use HasHttpBrowser; - - protected function httpBrowserBaseUri(): string - { - return 'https://symfony.com'; - } - - public function testDemo(): void - { - $this->browser() - ->visit('/my/page') // will make a real request to https://symfony.com/my/page - ->assertSuccessful() - ; - } -} -``` - -Alternatively, have your test extend `PantherTestCase` (requires `symfony/panther`) to -use the webserver for your app that panther provides. In this case, you do not need to -override the `httpBrowserBaseUri()` method. +This browser has no extra methods. ### PantherBrowser *The `PantherBrowser` is experimental in 1.0 and may be subject to BC Breaks.* -This browser is a wrapper for `Symfony\Component\Panther\Client` (requires `symfony/panther`). -To use in your functional tests, have a `PantherTestCase` test use the `HasPantherBrowser` trait: - -```php -namespace App\Tests; - -use Symfony\Component\Panther\PantherTestCase; -use Zenstruck\Browser\Test\HasPantherBrowser; - -class MyTest extends PantherTestCase -{ - use HasPantherBrowser; - - public function testDemo(): void - { - $this->browser() - ->visit('/my/page') - ->assertSee('My Title') - ; - } -} -``` - -#### PantherBrowser Specific Methods +This browser has the following extra methods: ```php /** @var \Zenstruck\Browser\PantherBrowser $browser **/ @@ -429,28 +402,28 @@ $browser ### Multiple Browser Instances -Within your test, you can call `->browser()` multiple times to get different -browser instances. This could be useful for testing an app with real-time -capabilities (ie websockets): +Within your test, you can call `->xBrowser()` methods multiple times to get +different browser instances. This could be useful for testing an app with +real-time capabilities (ie websockets): ```php namespace App\Tests; use Symfony\Component\Panther\PantherTestCase; -use Zenstruck\Browser\Test\HasPantherBrowser; +use Zenstruck\Browser\Test\HasBrowser; class MyTest extends PantherTestCase { - use HasPantherBrowser; + use HasBrowser; public function testDemo(): void { - $browser1 = $this->browser() + $browser1 = $this->pantherBrowser() ->visit('/my/page') // ... ; - $browser2 = $this->browser() + $browser2 = $this->pantherBrowser() ->visit('/my/page') // ... ; @@ -460,13 +433,15 @@ class MyTest extends PantherTestCase ### Mailer Component +*Only available for `KernelBrowser`/`HttpBrowser`.* + You can make assertions about emails sent in the last request: ```php use Zenstruck\Browser\Component\Mailer; use Zenstruck\Browser\Component\Mailer\TestEmail; -/** @var \Zenstruck\Browser $browser **/ +/** @var \Zenstruck\Browser\KernelBrowser|\Zenstruck\Browser\HttpBrowser $browser **/ $browser ->visit('/page/that/does/not/send/email') ->use(function(Mailer $component) { @@ -508,33 +483,31 @@ and `assertEmailSentTo()` methods right onto your custom browser. ### Test Browser Configuration You can configure default options or a starting state for your browser in your tests by -overriding the `configureBrowser()` method: +overriding the `xBrowser()` method from the `HasBrowser` trait: ```php namespace App\Tests; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Zenstruck\Browser; use Zenstruck\Browser\KernelBrowser; -use Zenstruck\Browser\Test\HasKernelBrowser; +use Zenstruck\Browser\Test\HasBrowser; class MyTest extends KernelTestCase { - use HasKernelBrowser; + use HasBrowser { + kernelBrowser as baseKernelBrowser; + } public function testDemo(): void { - $this->browser() + $this->kernelBrowser() ->assertOn('/') // browser always starts on the homepage (as defined below) ; } - /** - * @param Browser|KernelBrowser $browser - */ - protected function configureBrowser(Browser $browser): void + protected function kernelBrowser(): KernelBrowser { - $browser + return $this->baseKernelBrowser() ->interceptRedirects() // always intercept redirects ->throwExceptions() // always throw exceptions ->visit('/') // always start on the homepage @@ -657,17 +630,18 @@ If you find yourself creating a lot of [http requests](#http-requests) with the namespace App\Tests; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; - use Zenstruck\Browser; use Zenstruck\Browser\KernelBrowser; - use Zenstruck\Browser\Test\HasKernelBrowser; + use Zenstruck\Browser\Test\HasBrowser; class MyTest extends KernelTestCase { - use HasKernelBrowser; + use HasBrowser { + kernelBrowser as baseKernelBrowser; + } public function testDemo(): void { - $this->browser() + $this->kernelBrowser() // all http requests in this test class will have the X-Token header ->get('/endpoint') @@ -675,13 +649,12 @@ If you find yourself creating a lot of [http requests](#http-requests) with the ->get('/endpoint', ['headers' => ['Another' => 'Header']]) ; } - - /** - * @param Browser|KernelBrowser $browser - */ - protected function configureBrowser(Browser $browser): void + + protected function httpBrowser(): KernelBrowser { - $browser->setDefaultHttpOptions(['headers' => ['X-Token' => 'my-token']]); + return $this->baseKernelBrowser() + ->setDefaultHttpOptions(['headers' => ['X-Token' => 'my-token']]) + ; } } ``` @@ -724,8 +697,8 @@ If you find yourself creating a lot of [http requests](#http-requests) with the ### Custom Browser It is likely you will want to add your own actions and assertions. You can do this -by creating your own *Browser* that extends `Zenstruck\Browser` (or one of the implementations). -You can then add your own actions/assertions by using the base browser methods. +by creating your own *Browser* that extends one of the implementations. You can then +add your own actions/assertions by using the base browser methods. ```php namespace App\Tests; @@ -741,50 +714,34 @@ class AppBrowser extends KernelBrowser } ``` -Then in your test case, (depending on the base browser), override the `xBrowserClass()` -method and return your custom class: +Then, depending on the implementation you extended from, set the appropriate env variable: + +* `KernelBrowser`: `KERNEL_BROWSER_CLASS` +* `HttpBrowser`: `HTTP_BROWSER_CLASS` +* `PantherBrowser`: `PANTHER_BROWSER_CLASS` + +For the example above, you would set `KERNEL_BROWSER_CLASS=App\Tests\AppBrowser`. + +**TIP**: Create a base functional test case so all your tests can use your +custom browser and use the `@method` annotation to ensure your tests can +autocomplete your custom methods: ```php namespace App\Tests; +use App\Tests\AppBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Zenstruck\Browser\Test\HasKernelBrowser; +use Zenstruck\Browser\Test\HasBrowser; /** - * @method AppBrowser browser() This will help your IDE with typehints + * @method AppBrowser kernelBrowser() */ -class MyTest extends WebTestCase +abstract class MyTest extends WebTestCase { - use HasKernelBrowser; - - /** - * Alternatively, set the appropriate env variable: KERNEL_BROWSER_CLASS=App\Tests\AppBrowser - */ - protected static function kernelBrowserClass(): string - { - return AppBrowser::class; - } - - public function testDemo(): void - { - $this->browser() - ->visit('/my/page') - ->assertHasToolbar() - ; - } + use HasBrowser; } ``` -**TIP**: Create a base functional test case so all your tests can use your -custom browser. - -Each Browser type, and their corresponding test trait have their own class method and -env variable: - -1. `KernelBrowser`/`HasKernelBrowser`: `kernelBrowserClass()`/`KERNEL_BROWSER_CLASS` -2. `HttpBrowser`/`HasHttpBrowser`: `httpBrowserClass()`/`HTTP_BROWSER_CLASS` -3. `PantherBrowser`/`HasPantherBrowser`: `pantherBrowserClass()`/`PANTHER_BROWSER_CLASS` - ### Extensions There are several packaged extensions. These are traits that can be added to a @@ -813,7 +770,7 @@ Use in your tests: ```php public function testDemo(): void { - $this->browser() + $this->kernelBrowser() ->visit('/page/that/does/not/send/email') ->assertNoEmailSent() @@ -850,7 +807,7 @@ Use in your tests: ```php public function testDemo(): void { - $this->browser() + $this->kernelBrowser() // goes to the /login page, fills email/password fields, // and presses the Login button ->loginAs('kevin@example.com', 'password') diff --git a/src/Browser.php b/src/Browser.php index cd96c40..b2da774 100644 --- a/src/Browser.php +++ b/src/Browser.php @@ -31,6 +31,20 @@ public function __construct(DriverInterface $driver) $this->mink = new Mink([self::SESSION => new Session($driver)]); } + /** + * @return static + */ + public static function create(callable $factory): self + { + $browser = $factory(); + + if (!$browser instanceof self) { + throw new \RuntimeException(\sprintf('The factory callable must return an instance of "%s".', self::class)); + } + + return $browser; + } + /** * @return static */ diff --git a/src/Browser/Extension/ContainerAware.php b/src/Browser/Extension/ContainerAware.php deleted file mode 100644 index ea5fcf8..0000000 --- a/src/Browser/Extension/ContainerAware.php +++ /dev/null @@ -1,27 +0,0 @@ - - */ -trait ContainerAware -{ - private ?ContainerInterface $container = null; - - final public function setContainer(?ContainerInterface $container = null): void - { - $this->container = $container; - } - - final public function container(): ContainerInterface - { - if (!$this->container) { - throw new \RuntimeException('Container has not been set.'); - } - - return $this->container; - } -} diff --git a/src/Browser/HttpBrowser.php b/src/Browser/HttpBrowser.php index a33abcd..b80bb79 100644 --- a/src/Browser/HttpBrowser.php +++ b/src/Browser/HttpBrowser.php @@ -3,38 +3,44 @@ namespace Zenstruck\Browser; use Symfony\Component\BrowserKit\HttpBrowser as SymfonyHttpBrowser; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\HttpKernel\Profiler\Profile; -use Zenstruck\Browser\Extension\ContainerAware; +use Symfony\Component\HttpKernel\Profiler\Profiler; /** * @author Kevin Bond * * @method SymfonyHttpBrowser inner() */ -class HttpBrowser extends BrowserKitBrowser implements ContainerAwareInterface, ProfileAware +class HttpBrowser extends BrowserKitBrowser implements ProfileAware { - use ContainerAware; + private ?Profiler $profiler = null; final public function __construct(SymfonyHttpBrowser $inner) { parent::__construct($inner); } + final public function setProfiler(Profiler $profiler): self + { + $this->profiler = $profiler; + + return $this; + } + /** * Profile collection must be enabled globally for this feature. */ final public function profile(): Profile { - if (!$this->container()->has('profiler')) { - throw new \RuntimeException('Profiling is not enabled.'); + if (!$this->profiler) { + throw new \RuntimeException('The profiler has not been set. Is profiling enabled?'); } if (!$token = $this->inner()->getInternalResponse()->getHeader('x-debug-token')) { throw new \RuntimeException('Profiling is not enabled for this request. You must enable profile collection globally when using the HttpBrowser.'); } - if (!$profile = $this->container()->get('profiler')->loadProfile($token)) { + if (!$profile = $this->profiler->loadProfile($token)) { throw new \RuntimeException('Could not find profile for this request.'); } diff --git a/src/Browser/Test/HasBrowser.php b/src/Browser/Test/HasBrowser.php index a2dbe2c..990191c 100644 --- a/src/Browser/Test/HasBrowser.php +++ b/src/Browser/Test/HasBrowser.php @@ -3,47 +3,160 @@ namespace Zenstruck\Browser\Test; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Zenstruck\Browser; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\BrowserKit\HttpBrowser as HttpBrowserClient; +use Symfony\Component\Panther\Client as PantherClient; +use Symfony\Component\Panther\PantherTestCase; +use Zenstruck\Browser\HttpBrowser; +use Zenstruck\Browser\KernelBrowser; +use Zenstruck\Browser\PantherBrowser; /** * @author Kevin Bond */ trait HasBrowser { - final protected function browser(): Browser + /** @var HttpBrowserClient[] */ + private static array $httpBrowserClients = []; + private static ?PantherClient $primaryPantherClient = null; + + /** + * @internal + * @after + */ + final public static function _resetBrowserClients(): void { - $browser = $this->createBrowser() + self::$httpBrowserClients = []; + self::$primaryPantherClient = null; + } + + protected function pantherBrowser(): PantherBrowser + { + $browser = PantherBrowser::create(function() { + if (!$this instanceof PantherTestCase) { + throw new \RuntimeException(\sprintf('The "%s" method can only be used on TestCases that extend "%s".', __METHOD__, PantherTestCase::class)); + } + + $class = $_SERVER['PANTHER_BROWSER_CLASS'] ?? PantherBrowser::class; + + if (!\is_a($class, PantherBrowser::class, true)) { + throw new \RuntimeException(\sprintf('"PANTHER_BROWSER_CLASS" env variable must reference a class that extends %s.', PantherBrowser::class)); + } + + if (self::$primaryPantherClient) { + return new $class(static::createAdditionalPantherClient()); + } + + self::$primaryPantherClient = static::createPantherClient( + ['browser' => $_SERVER['PANTHER_BROWSER'] ?? static::CHROME] + ); + + return new $class(self::$primaryPantherClient); + }); + + BrowserExtension::registerBrowser($browser); + + return $browser ->setSourceDir($_SERVER['BROWSER_SOURCE_DIR'] ?? './var/browser/source') + ->setScreenshotDir($_SERVER['BROWSER_SCREENSHOT_DIR'] ?? './var/browser/screenshots') + ->setConsoleLogDir($_SERVER['BROWSER_CONSOLE_LOG_DIR'] ?? './var/browser/console-logs') ; + } - BrowserExtension::registerBrowser($browser); + protected function httpBrowser(): HttpBrowser + { + $browser = HttpBrowser::create(function() { + $class = $_SERVER['HTTP_BROWSER_CLASS'] ?? HttpBrowser::class; - if (!$this instanceof KernelTestCase) { - $this->configureBrowser($browser); + if (!\is_a($class, HttpBrowser::class, true)) { + throw new \RuntimeException(\sprintf('"HTTP_BROWSER_CLASS" env variable must reference a class that extends %s.', HttpBrowser::class)); + } + + $baseUri = $_SERVER['HTTP_BROWSER_URI'] ?? null; + + if (!$baseUri && !$this instanceof PantherTestCase) { + throw new \RuntimeException(\sprintf('If not using "HTTP_BROWSER_URI", your TestCase must extend "%s".', PantherTestCase::class)); + } + + if (!$baseUri) { + self::startWebServer(); + + $baseUri = self::$baseUri; + } + + // copied from PantherTestCaseTrait::createHttpBrowserClient() + $client = new HttpBrowserClient(); + $urlComponents = \parse_url($baseUri); + $host = $urlComponents['host']; + + if (isset($urlComponents['port'])) { + $host .= ":{$urlComponents['port']}"; + } + + $client->setServerParameter('HTTP_HOST', $host); + + if ('https' === ($urlComponents['scheme'] ?? 'http')) { + $client->setServerParameter('HTTPS', 'true'); + } + + /** @var HttpBrowser $browser */ + $browser = new $class(self::$httpBrowserClients[] = $client); + + if (!$this instanceof KernelTestCase) { + return $browser; + } + + if (!static::$booted) { + static::bootKernel(); + } + + if (static::$container->has('profiler')) { + $browser->setProfiler(static::$container->get('profiler')); + } return $browser; + }); + + BrowserExtension::registerBrowser($browser); + + return $browser + ->setSourceDir($_SERVER['BROWSER_SOURCE_DIR'] ?? './var/browser/source') + ; + } + + protected function kernelBrowser(): KernelBrowser + { + if (!$this instanceof KernelTestCase) { + throw new \RuntimeException(\sprintf('The "%s" method can only be used on TestCases that extend "%s".', __METHOD__, KernelTestCase::class)); } - if (!static::$booted) { + $browser = KernelBrowser::create(function() { + $class = $_SERVER['KERNEL_BROWSER_CLASS'] ?? KernelBrowser::class; + + if (!\is_a($class, KernelBrowser::class, true)) { + throw new \RuntimeException(\sprintf('"KERNEL_BROWSER_CLASS" env variable must reference a class that extends %s.', KernelBrowser::class)); + } + + if ($this instanceof WebTestCase) { + static::ensureKernelShutdown(); + + return new $class(static::createClient()); + } + + // reboot kernel before starting browser static::bootKernel(); - } - if ($browser instanceof ContainerAwareInterface) { - $browser->setContainer(static::$container); - } + if (!static::$container->has('test.client')) { + throw new \RuntimeException('The Symfony test client is not enabled.'); + } - $this->configureBrowser($browser); + return new $class(static::$container->get('test.client')); + }); - return $browser; - } + BrowserExtension::registerBrowser($browser); - /** - * Override to configure the Browser's initial state/options. - */ - protected function configureBrowser(Browser $browser): void - { + return $browser + ->setSourceDir($_SERVER['BROWSER_SOURCE_DIR'] ?? './var/browser/source') + ; } - - abstract protected function createBrowser(): Browser; } diff --git a/src/Browser/Test/HasHttpBrowser.php b/src/Browser/Test/HasHttpBrowser.php deleted file mode 100644 index 18a913f..0000000 --- a/src/Browser/Test/HasHttpBrowser.php +++ /dev/null @@ -1,72 +0,0 @@ - - * - * @method HttpBrowser browser() - */ -trait HasHttpBrowser -{ - use HasBrowser; - - /** @var HttpBrowserClient[] */ - private static array $httpBrowserClients = []; - - /** - * @internal - * @after - */ - public static function _resetHttpBrowserClients(): void - { - self::$httpBrowserClients = []; - } - - protected function createBrowser(): HttpBrowser - { - $class = static::httpBrowserClass(); - - if (!\is_a($class, HttpBrowser::class, true)) { - throw new \RuntimeException(\sprintf('"HTTP_BROWSER_CLASS" env variable must reference a class that extends %s.', HttpBrowser::class)); - } - - $client = new HttpBrowserClient(); - $urlComponents = \parse_url($this->httpBrowserBaseUri()); - - // copied from PantherTestCaseTrait::createHttpBrowserClient() - $host = $urlComponents['host']; - - if (isset($urlComponents['port'])) { - $host .= ":{$urlComponents['port']}"; - } - - $client->setServerParameter('HTTP_HOST', $host); - - if ('https' === ($urlComponents['scheme'] ?? 'http')) { - $client->setServerParameter('HTTPS', 'true'); - } - - return new $class(self::$httpBrowserClients[] = $client); - } - - protected function httpBrowserBaseUri(): string - { - if (!$this instanceof PantherTestCase) { - throw new \RuntimeException(\sprintf('If not using "%s", you must override "%s" and return a base uri.', PantherTestCase::class, __METHOD__)); - } - - self::startWebServer(); - - return self::$baseUri; - } - - protected static function httpBrowserClass(): string - { - return $_SERVER['HTTP_BROWSER_CLASS'] ?? HttpBrowser::class; - } -} diff --git a/src/Browser/Test/HasKernelBrowser.php b/src/Browser/Test/HasKernelBrowser.php deleted file mode 100644 index 0a89417..0000000 --- a/src/Browser/Test/HasKernelBrowser.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * @method KernelBrowser browser() - */ -trait HasKernelBrowser -{ - use HasBrowser; - - protected function createBrowser(): KernelBrowser - { - if (!$this instanceof KernelTestCase) { - throw new \RuntimeException(\sprintf('The "%s" trait can only be used on TestCases that extend "%s".', __TRAIT__, KernelTestCase::class)); - } - - $class = static::kernelBrowserClass(); - - if (!\is_a($class, KernelBrowser::class, true)) { - throw new \RuntimeException(\sprintf('"KERNEL_BROWSER_CLASS" env variable must reference a class that extends %s.', KernelBrowser::class)); - } - - if ($this instanceof WebTestCase) { - static::ensureKernelShutdown(); - - return new $class(static::createClient()); - } - - // reboot kernel before starting browser - static::bootKernel(); - - if (!static::$container->has('test.client')) { - throw new \RuntimeException('The Symfony test client is not enabled.'); - } - - return new $class(static::$container->get('test.client')); - } - - protected static function kernelBrowserClass(): string - { - return $_SERVER['KERNEL_BROWSER_CLASS'] ?? KernelBrowser::class; - } -} diff --git a/src/Browser/Test/HasPantherBrowser.php b/src/Browser/Test/HasPantherBrowser.php deleted file mode 100644 index fe2c583..0000000 --- a/src/Browser/Test/HasPantherBrowser.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * @experimental in 1.0 - * - * @method PantherBrowser browser() - */ -trait HasPantherBrowser -{ - use HasBrowser; - - private static ?Client $primaryPantherClient = null; - - /** - * @internal - * @after - */ - public static function _resetPrimaryPantherClient(): void - { - self::$primaryPantherClient = null; - } - - protected function createBrowser(): PantherBrowser - { - return $this->createPantherBrowser() - ->setScreenshotDir($_SERVER['BROWSER_SCREENSHOT_DIR'] ?? './var/browser/screenshots') - ->setConsoleLogDir($_SERVER['BROWSER_CONSOLE_LOG_DIR'] ?? './var/browser/console-logs') - ; - } - - protected static function pantherBrowserClass(): string - { - return $_SERVER['PANTHER_BROWSER_CLASS'] ?? PantherBrowser::class; - } - - private function createPantherBrowser(): PantherBrowser - { - if (!$this instanceof PantherTestCase) { - throw new \RuntimeException(\sprintf('The "%s" trait can only be used on TestCases that extend "%s".', __TRAIT__, PantherTestCase::class)); - } - - $class = static::pantherBrowserClass(); - - if (!\is_a($class, PantherBrowser::class, true)) { - throw new \RuntimeException(\sprintf('"PANTHER_BROWSER_CLASS" env variable must reference a class that extends %s.', PantherBrowser::class)); - } - - if (self::$primaryPantherClient) { - return new $class(static::createAdditionalPantherClient()); - } - - return new $class(self::$primaryPantherClient = static::createPantherClient(['browser' => $_SERVER['PANTHER_BROWSER'] ?? static::CHROME])); - } -} diff --git a/tests/BrowserTests.php b/tests/BrowserTests.php index 5b522fb..8cd6b33 100644 --- a/tests/BrowserTests.php +++ b/tests/BrowserTests.php @@ -4,6 +4,7 @@ use Symfony\Component\VarDumper\VarDumper; use Zenstruck\Browser; +use Zenstruck\Browser\Test\HasBrowser; use Zenstruck\Browser\Tests\Extension\HtmlTests; use Zenstruck\Browser\Tests\Fixture\TestComponent1; use Zenstruck\Browser\Tests\Fixture\TestComponent2; @@ -13,7 +14,7 @@ */ trait BrowserTests { - use HtmlTests; + use HasBrowser, HtmlTests; /** * @test @@ -128,12 +129,14 @@ public function component_pre_assertions_and_actions_are_called(): void */ public function with_can_accept_multiple_browsers_and_components(): void { - $this->browser() - ->use(function(Browser $browser1, $browser2, TestComponent1 $component1, TestComponent2 $component2) { + $browser = $this->browser(); + + $browser + ->use(function(Browser $browser1, $browser2, TestComponent1 $component1, TestComponent2 $component2) use ($browser) { $this->assertInstanceOf(Browser::class, $browser1); $this->assertInstanceOf(Browser::class, $browser2); - $this->assertInstanceOf($this->browserClass(), $browser1); - $this->assertInstanceOf($this->browserClass(), $browser2); + $this->assertInstanceOf(\get_class($browser), $browser1); + $this->assertInstanceOf(\get_class($browser), $browser2); $this->assertInstanceOf(TestComponent1::class, $component1); $this->assertInstanceOf(TestComponent2::class, $component2); }) @@ -226,5 +229,5 @@ public function can_save_source(): void \unlink($file); } - abstract protected static function browserClass(): string; + abstract protected function browser(): Browser; } diff --git a/tests/ConfigureBrowserTest.php b/tests/ConfigureBrowserTest.php index db0104b..d4a04d2 100644 --- a/tests/ConfigureBrowserTest.php +++ b/tests/ConfigureBrowserTest.php @@ -3,26 +3,28 @@ namespace Zenstruck\Browser\Tests; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Zenstruck\Browser; -use Zenstruck\Browser\Test\HasKernelBrowser; +use Zenstruck\Browser\KernelBrowser; +use Zenstruck\Browser\Test\HasBrowser; /** * @author Kevin Bond */ final class ConfigureBrowserTest extends WebTestCase { - use HasKernelBrowser; + use HasBrowser { + kernelBrowser as baseKernelBrowser; + } /** * @test */ public function browser_has_been_configured(): void { - $this->browser()->assertOn('/page1'); + $this->kernelBrowser()->assertOn('/page1'); } - protected function configureBrowser(Browser $browser): void + protected function kernelBrowser(): KernelBrowser { - $browser->visit('/page1'); + return $this->baseKernelBrowser()->visit('/page1'); } } diff --git a/tests/HttpBrowserTest.php b/tests/HttpBrowserTest.php index e728f8c..034341e 100644 --- a/tests/HttpBrowserTest.php +++ b/tests/HttpBrowserTest.php @@ -4,17 +4,16 @@ use Symfony\Component\Panther\PantherTestCase; use Zenstruck\Browser\HttpBrowser; -use Zenstruck\Browser\Test\HasHttpBrowser; /** * @author Kevin Bond */ final class HttpBrowserTest extends PantherTestCase { - use BrowserKitBrowserTests, HasHttpBrowser; + use BrowserKitBrowserTests; - protected static function browserClass(): string + protected function browser(): HttpBrowser { - return HttpBrowser::class; + return $this->httpBrowser(); } } diff --git a/tests/KernelBrowserTests.php b/tests/KernelBrowserTests.php index 6961796..d1331e7 100644 --- a/tests/KernelBrowserTests.php +++ b/tests/KernelBrowserTests.php @@ -5,14 +5,13 @@ use Symfony\Bundle\FrameworkBundle\KernelBrowser as SymfonyKernelBrowser; use Symfony\Component\Security\Core\User\User; use Zenstruck\Browser\KernelBrowser; -use Zenstruck\Browser\Test\HasKernelBrowser; /** * @author Kevin Bond */ trait KernelBrowserTests { - use BrowserKitBrowserTests, HasKernelBrowser; + use BrowserKitBrowserTests; /** * @test @@ -81,8 +80,8 @@ public function can_enable_the_profiler(): void $this->assertTrue($profile->hasCollector('request')); } - protected static function browserClass(): string + protected function browser(): KernelBrowser { - return KernelBrowser::class; + return $this->kernelBrowser(); } } diff --git a/tests/NonPantherHttpBrowserTest.php b/tests/NonPantherHttpBrowserTest.php index bbe112d..81df6ab 100644 --- a/tests/NonPantherHttpBrowserTest.php +++ b/tests/NonPantherHttpBrowserTest.php @@ -3,30 +3,39 @@ namespace Zenstruck\Browser\Tests; use PHPUnit\Framework\TestCase; -use Zenstruck\Browser\Test\HasHttpBrowser; +use Zenstruck\Browser\Test\HasBrowser; /** * @author Kevin Bond */ final class NonPantherHttpBrowserTest extends TestCase { - use HasHttpBrowser; + use HasBrowser; + + protected function setUp(): void + { + parent::setUp(); + + $_SERVER['HTTP_BROWSER_URI'] = 'https://symfony.com'; + } + + protected function tearDown(): void + { + parent::tearDown(); + + unset($_SERVER['HTTP_BROWSER_URI']); + } /** * @test */ public function can_navigate_symfony_site(): void { - $this->browser() + $this->httpBrowser() ->visit('/') ->follow('Documentation') ->assertSuccessful() ->assertOn('/doc/current/index.html') ; } - - protected function httpBrowserBaseUri(): string - { - return 'https://symfony.com'; - } } diff --git a/tests/PantherBrowserTest.php b/tests/PantherBrowserTest.php index 34e3df4..a11349e 100644 --- a/tests/PantherBrowserTest.php +++ b/tests/PantherBrowserTest.php @@ -5,7 +5,6 @@ use Symfony\Component\Panther\PantherTestCase; use Symfony\Component\VarDumper\VarDumper; use Zenstruck\Browser\PantherBrowser; -use Zenstruck\Browser\Test\HasPantherBrowser; /** * @author Kevin Bond @@ -14,7 +13,7 @@ */ final class PantherBrowserTest extends PantherTestCase { - use BrowserTests, HasPantherBrowser; + use BrowserTests; /** * @test @@ -173,8 +172,8 @@ public function can_dump_console_log(): void $this->assertStringContainsString('error!', $dumpedValues[0][0]['message']); } - protected static function browserClass(): string + protected function browser(): PantherBrowser { - return PantherBrowser::class; + return $this->pantherBrowser(); } }