diff --git a/CHANGELOG.md b/CHANGELOG.md index 87fc49a..e4cd0a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # CHANGELOG +## [v1.9.1](https://github.com/zenstruck/browser/releases/tag/v1.9.1) + +November 5th, 2024 - [v1.9.0...v1.9.1](https://github.com/zenstruck/browser/compare/v1.9.0...v1.9.1) + +* 53bbc83 minor: unpack Foundry 2 proxies (#160) by @kbond + +## [v1.9.0](https://github.com/zenstruck/browser/releases/tag/v1.9.0) + +October 20th, 2024 - [v1.8.1...v1.9.0](https://github.com/zenstruck/browser/compare/v1.8.1...v1.9.0) + +* 6175462 feat: add `BROWSER_ALWAYS_START_WEBSERVER` env var (#156) by @kbond +* d3a52e9 feat: deprecate foundry integration (#154) by @kbond +* 3b4d4a4 minor: fix tests (#154) by @kbond +* d90bad9 minor: sca (#154) by @kbond + ## [v1.8.1](https://github.com/zenstruck/browser/releases/tag/v1.8.1) February 21st, 2024 - [v1.8.0...v1.8.1](https://github.com/zenstruck/browser/compare/v1.8.0...v1.8.1) diff --git a/README.md b/README.md index 356a2bc..6816f54 100644 --- a/README.md +++ b/README.md @@ -320,9 +320,6 @@ $browser // authenticate a user for subsequent actions ->actingAs($user) // \Symfony\Component\Security\Core\User\UserInterface - // If using zenstruck/foundry, you can pass a factory/proxy - ->actingAs(UserFactory::new()) - // fail if authenticated ->assertNotAuthenticated() @@ -332,8 +329,7 @@ $browser // fails if NOT authenticated as "kbond" ->assertAuthenticated('kbond') - // \Symfony\Component\Security\Core\User\UserInterface or, if using - // zenstruck/foundry, you can pass a factory/proxy + // \Symfony\Component\Security\Core\User\UserInterface ->assertAuthenticated($user) ; ``` @@ -462,7 +458,15 @@ $json = $browser ### PantherBrowser -*The `PantherBrowser` is experimental in 1.0 and may be subject to BC Breaks.* +> [!NOTE] +> The `PantherBrowser` is experimental in 1.0 and may be subject to BC Breaks. + +> [!TIP] +> By default, Panther will not start a web server if it detects one already running +> with the Symfony CLI. This is likely running in your `dev` environment and will cause +> unexpected test failures. Set the env variable `BROWSER_ALWAYS_START_WEBSERVER=1` +> to always start a webserver configured for your current test env when running +> Panther tests. This browser has the following extra methods: @@ -666,17 +670,18 @@ $browser->assertSeeElement(ProductLinkSelector('Product 1', 'Edit')); There are several environment variables available to configure: -| Variable | Description | Default | -|----------------------------|--------------------------------------------------------------------------------------------|------------------------------------| -| `BROWSER_SOURCE_DIR` | Directory to save source files to. | `./var/browser/source` | -| `BROWSER_SCREENSHOT_DIR` | Directory to save screenshots to (only applies to `PantherBrowser`). | `./var/browser/screenshots` | -| `BROWSER_CONSOLE_LOG_DIR` | Directory to save javascript console logs to (only applies to `PantherBrowser`). | `./var/browser/console-logs` | -| `BROWSER_FOLLOW_REDIRECTS` | Whether to follow redirects by default (only applies to `KernelBrowser`). | `1` _(true)_ | -| `BROWSER_CATCH_EXCEPTIONS` | Whether to catch exceptions by default (only applies to `KernelBrowser`). | `1` _(true)_ | -| `BROWSER_SOURCE_DEBUG` | Whether to add request metadata to written source files (only applies to `KernelBrowser`). | `0` _(false)_ | -| `KERNEL_BROWSER_CLASS` | `KernelBrowser` class to use. | `Zenstruck\Browser\KernelBrowser` | -| `PANTHER_BROWSER_CLASS` | `PantherBrowser` class to use. | `Zenstruck\Browser\PantherBrowser` | -| `PANTHER_NO_HEADLESS` | Disable headless-mode and allow usage of `PantherBrowser::pause()`. | `0` _(false)_ | +| Variable | Description | Default | +|----------------------------------|------------------------------------------------------------------------------------------------------------------------|------------------------------------| +| `BROWSER_SOURCE_DIR` | Directory to save source files to. | `./var/browser/source` | +| `BROWSER_SCREENSHOT_DIR` | Directory to save screenshots to (only applies to `PantherBrowser`). | `./var/browser/screenshots` | +| `BROWSER_CONSOLE_LOG_DIR` | Directory to save javascript console logs to (only applies to `PantherBrowser`). | `./var/browser/console-logs` | +| `BROWSER_FOLLOW_REDIRECTS` | Whether to follow redirects by default (only applies to `KernelBrowser`). | `1` _(true)_ | +| `BROWSER_CATCH_EXCEPTIONS` | Whether to catch exceptions by default (only applies to `KernelBrowser`). | `1` _(true)_ | +| `BROWSER_SOURCE_DEBUG` | Whether to add request metadata to written source files (only applies to `KernelBrowser`). | `0` _(false)_ | +| `KERNEL_BROWSER_CLASS` | `KernelBrowser` class to use. | `Zenstruck\Browser\KernelBrowser` | +| `PANTHER_BROWSER_CLASS` | `PantherBrowser` class to use. | `Zenstruck\Browser\PantherBrowser` | +| `PANTHER_NO_HEADLESS` | Disable headless-mode and allow usage of `PantherBrowser::pause()`. | `0` _(false)_ | +| `BROWSER_ALWAYS_START_WEBSERVER` | Always start a webserver configured for your current test env before running tests (only applies to `PantherBrowser`). | `0` _(false)_ | ## Extending diff --git a/composer.json b/composer.json index a2ee520..2c9605a 100644 --- a/composer.json +++ b/composer.json @@ -23,15 +23,14 @@ }, "require-dev": { "dbrekelmans/bdi": "^1.0", - "justinrainbow/json-schema": "^5.2.13", + "justinrainbow/json-schema": "^5.3", "mtdowling/jmespath.php": "^2.6", "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^9.6|^10.4", + "phpunit/phpunit": "^9.6.21|^10.4", "symfony/mime": "^6.4|^7.0", "symfony/panther": "^2.1.0", "symfony/phpunit-bridge": "^6.0|^7.0", - "symfony/security-bundle": "^6.4|^7.0", - "zenstruck/foundry": "^1.30" + "symfony/security-bundle": "^6.4|^7.0" }, "suggest": { "justinrainbow/json-schema": "Json schema validator. Needed to use Json::assertMatchesSchema().", diff --git a/src/Browser/KernelBrowser.php b/src/Browser/KernelBrowser.php index babbca4..52bb607 100644 --- a/src/Browser/KernelBrowser.php +++ b/src/Browser/KernelBrowser.php @@ -23,7 +23,8 @@ use Zenstruck\Callback\Parameter; use Zenstruck\Dom\Selector; use Zenstruck\Foundry\Factory; -use Zenstruck\Foundry\Proxy; +use Zenstruck\Foundry\Persistence\Proxy; +use Zenstruck\Foundry\Proxy as LegacyProxy; /** * @author Kevin Bond @@ -135,18 +136,23 @@ final public function withProfiling(): self } /** - * @param UserInterface|Proxy|Factory $user + * @param UserInterface $user * * @return static */ public function actingAs(object $user, ?string $firewall = null): self { - if ($user instanceof Factory) { - $user = $user->create(); + if ($user instanceof Factory) { // @phpstan-ignore-line + trigger_deprecation('zenstruck/browser', '1.9', 'Passing a Factory to actingAs() is deprecated, pass the created object instead.'); + $user = $user->create(); // @phpstan-ignore-line } - if ($user instanceof Proxy) { - $user = $user->object(); + if ($user instanceof LegacyProxy) { // @phpstan-ignore-line + $user = $user->object(); // @phpstan-ignore-line + } + + if ($user instanceof Proxy) { // @phpstan-ignore-line + $user = $user->_real(); // @phpstan-ignore-line } if (!$user instanceof UserInterface) { @@ -159,7 +165,7 @@ public function actingAs(object $user, ?string $firewall = null): self } /** - * @param string|UserInterface|Proxy|Factory|null $as + * @param string|UserInterface|null $as * * @return static */ @@ -179,12 +185,17 @@ public function assertAuthenticated($as = null): self return $this; } - if ($as instanceof Factory) { - $as = $as->create(); + if ($as instanceof Factory) { // @phpstan-ignore-line + trigger_deprecation('zenstruck/browser', '1.9', 'Passing a Factory to assertAuthenticated() is deprecated, pass the created object instead.'); + $as = $as->create(); // @phpstan-ignore-line + } + + if ($as instanceof LegacyProxy) { // @phpstan-ignore-line + $as = $as->object(); // @phpstan-ignore-line } - if ($as instanceof Proxy) { - $as = $as->object(); + if ($as instanceof Proxy) { // @phpstan-ignore-line + $as = $as->_real(); // @phpstan-ignore-line } if ($as instanceof UserInterface) { diff --git a/src/Browser/Test/HasBrowser.php b/src/Browser/Test/HasBrowser.php index 0bc8f67..2e985bb 100644 --- a/src/Browser/Test/HasBrowser.php +++ b/src/Browser/Test/HasBrowser.php @@ -64,6 +64,11 @@ protected function pantherBrowser(array $options = [], array $kernelOptions = [] 'console_log_dir' => $_SERVER['BROWSER_CONSOLE_LOG_DIR'] ?? './var/browser/console-logs', ]; + if ($_SERVER['BROWSER_ALWAYS_START_WEBSERVER'] ?? null) { + $_SERVER['PANTHER_APP_ENV'] = $_SERVER['APP_ENV'] ?? 'test'; // use current environment + $_SERVER['SYMFONY_PROJECT_DEFAULT_ROUTE_URL'] = ''; // ignore existing server running with Symfony CLI + } + if (self::$primaryPantherClient) { $browser = new $class(static::createAdditionalPantherClient(), $browserOptions); } else { diff --git a/src/Browser/Test/LegacyExtension.php b/src/Browser/Test/LegacyExtension.php index 94f1d26..7842c27 100644 --- a/src/Browser/Test/LegacyExtension.php +++ b/src/Browser/Test/LegacyExtension.php @@ -122,7 +122,7 @@ private static function normalizeTestName(string $name): string \preg_match('#^(?[\w:\\\]+) with data set "(?.*)"#', $name, $matches); } - $normalized = \strtr($matches['test'], '\\:', '-_'); + $normalized = \strtr($matches['test'], '\\:', '-_'); // @phpstan-ignore-line if (isset($matches['dataset'])) { $normalized .= '__data-set-'.\preg_replace('/\W+/', '-', $matches['dataset']); diff --git a/tests/Fixture/Kernel.php b/tests/Fixture/Kernel.php index b501937..90b2044 100644 --- a/tests/Fixture/Kernel.php +++ b/tests/Fixture/Kernel.php @@ -28,7 +28,6 @@ use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; use Symfony\Component\Security\Core\User\InMemoryUser; -use Zenstruck\Foundry\ZenstruckFoundryBundle; /** * @author Kevin Bond @@ -173,7 +172,6 @@ public function registerBundles(): iterable { yield new FrameworkBundle(); yield new SecurityBundle(); - yield new ZenstruckFoundryBundle(); } protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader): void @@ -209,9 +207,6 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load } $c->loadFromExtension('security', $security); - $c->loadFromExtension('zenstruck_foundry', [ - 'auto_refresh_proxies' => false, - ]); $c->register('logger', NullLogger::class); // disable logging } diff --git a/tests/HttpOptionsTest.php b/tests/HttpOptionsTest.php index bccc5c9..bf9a0ab 100644 --- a/tests/HttpOptionsTest.php +++ b/tests/HttpOptionsTest.php @@ -196,7 +196,7 @@ public function json_ajax_constructor_with_no_value(): void */ public function create_with_self(): void { - $options = new class() extends HttpOptions {}; + $options = new class extends HttpOptions {}; $this->assertSame($options, HttpOptions::create($options)); } diff --git a/tests/KernelBrowserAuthenticationTest.php b/tests/KernelBrowserAuthenticationTest.php index 2ecaa36..96323ea 100644 --- a/tests/KernelBrowserAuthenticationTest.php +++ b/tests/KernelBrowserAuthenticationTest.php @@ -17,16 +17,13 @@ use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\User\InMemoryUser; use Zenstruck\Browser\Test\HasBrowser; -use Zenstruck\Foundry\Test\Factories; - -use function Zenstruck\Foundry\anonymous; /** * @author Kevin Bond */ final class KernelBrowserAuthenticationTest extends KernelTestCase { - use Factories, HasBrowser; + use HasBrowser; /** * @test @@ -41,36 +38,6 @@ public function can_act_as_user(): void ; } - /** - * @test - */ - public function can_act_as_user_with_foundry_factory(): void - { - $user = anonymous(InMemoryUser::class, ['username' => 'kevin', 'password' => 'pass']); - - $this->browser() - ->throwExceptions() - ->actingAs($user) - ->visit('/user') - ->assertSee('user: kevin/pass') - ; - } - - /** - * @test - */ - public function can_act_as_user_with_foundry_proxy(): void - { - $user = anonymous(InMemoryUser::class)->create(['username' => 'kevin', 'password' => 'pass']); - - $this->browser() - ->throwExceptions() - ->actingAs($user) - ->visit('/user') - ->assertSee('user: kevin/pass') - ; - } - /** * @test */ @@ -78,8 +45,6 @@ public function can_make_authentication_assertions(): void { $username = 'kevin'; $user = new InMemoryUser('kevin', 'pass'); - $factory = anonymous(InMemoryUser::class, ['username' => 'kevin', 'password' => 'pass']); - $proxy = anonymous(InMemoryUser::class)->create(['username' => 'kevin', 'password' => 'pass']); $this->browser() ->assertNotAuthenticated() @@ -87,8 +52,6 @@ public function can_make_authentication_assertions(): void ->assertAuthenticated() ->assertAuthenticated($username) ->assertAuthenticated($user) - ->assertAuthenticated($factory) - ->assertAuthenticated($proxy) ->visit('/user') ->assertAuthenticated() ->assertAuthenticated($username) diff --git a/tests/NormalizationTest.php b/tests/NormalizationTest.php index 863a882..5a97619 100644 --- a/tests/NormalizationTest.php +++ b/tests/NormalizationTest.php @@ -42,8 +42,8 @@ public static function namesProvider(): \Generator $baseTemplate = 'error_'.__METHOD__; yield 'test name without datasets' => [ - 'test name' => __METHOD__, - 'expected output' => \strtr($baseTemplate, '\\:', '-_').'__0', + 'testName' => __METHOD__, + 'expectedOutput' => \strtr($baseTemplate, '\\:', '-_').'__0', ]; $datasetTemplate = $baseTemplate.'__data-set-%s__0'; @@ -55,20 +55,20 @@ public static function namesProvider(): \Generator $numericOutput = \strtr($numericTemplate, '\\:', '-_'); yield 'phpunit 10 alpha' => [ - 'test name' => __METHOD__.' with data set "test set"', - 'expected output' => $alphaOutput, + 'testName' => __METHOD__.' with data set "test set"', + 'expectedOutput' => $alphaOutput, ]; yield 'phpunit 10 numeric' => [ - 'test name' => __METHOD__.' with data set #0', - 'expected output' => $numericOutput, + 'testName' => __METHOD__.' with data set #0', + 'expectedOutput' => $numericOutput, ]; yield 'legacy alpha' => [ - 'test name' => __METHOD__.' with data set "test set" (test set)', - 'expected output' => $alphaOutput, + 'testName' => __METHOD__.' with data set "test set" (test set)', + 'expectedOutput' => $alphaOutput, ]; yield 'legacy numeric' => [ - 'test name' => __METHOD__.' with data set #0 (test set)', - 'expected output' => $numericOutput, + 'testName' => __METHOD__.' with data set #0 (test set)', + 'expectedOutput' => $numericOutput, ]; } @@ -76,28 +76,28 @@ public static function edgeCaseTestNames(): \Generator { $baseTemplate = \strtr('error_'.__METHOD__.'__data-set-', '\\:', '-_'); yield 'self within moustache' => [ - 'test name' => __METHOD__.' with data set "te{{self}}st" (test set)', - 'expected output' => $baseTemplate.'te-self-st__0', + 'testName' => __METHOD__.' with data set "te{{self}}st" (test set)', + 'expectedOutput' => $baseTemplate.'te-self-st__0', ]; yield 'double quoted with space' => [ - 'test name' => __METHOD__.' with data set "_self.env.setCache("uri://host.net:2121") _self.env.loadTemplate("other-host")" (test set)', - 'expected output' => $baseTemplate.'_self-env-setCache-uri-host-net-2121-_self-env-loadTemplate-other-host-__0', + 'testName' => __METHOD__.' with data set "_self.env.setCache("uri://host.net:2121") _self.env.loadTemplate("other-host")" (test set)', + 'expectedOutput' => $baseTemplate.'_self-env-setCache-uri-host-net-2121-_self-env-loadTemplate-other-host-__0', ]; yield 'double quotes in moustache' => [ - 'test name' => __METHOD__.' with data set "te{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}st"', - 'expected output' => $baseTemplate.'te-_self-env-registerUndefinedFilterCallback-exec-_self-env-getFilter-id-st__0', + 'testName' => __METHOD__.' with data set "te{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}st"', + 'expectedOutput' => $baseTemplate.'te-_self-env-registerUndefinedFilterCallback-exec-_self-env-getFilter-id-st__0', ]; yield 'escaped simple quote' => [ - 'test name' => __METHOD__.' with data set "te{{\'/etc/passwd\'|file_excerpt(1,30)}}st"', - 'expected output' => $baseTemplate.'te-etc-passwd-file_excerpt-1-30-st__0', - ]; + 'testName' => __METHOD__.' with data set "te{{\'/etc/passwd\'|file_excerpt(1,30)}}st"', + 'expectedOutput' => $baseTemplate.'te-etc-passwd-file_excerpt-1-30-st__0', + ]; yield 'single quote for array index access' => [ - 'test name' => __METHOD__.' with data set "te{{[\'id\']|filter(\'system\')}}st"', - 'expected output' => $baseTemplate.'te-id-filter-system-st__0', + 'testName' => __METHOD__.' with data set "te{{[\'id\']|filter(\'system\')}}st"', + 'expectedOutput' => $baseTemplate.'te-id-filter-system-st__0', ]; yield 'numeric array access' => [ - 'test name' => __METHOD__.' with data set "te{{[0]|reduce(\'system\',\'id\')}}st"', - 'expected output' => $baseTemplate.'te-0-reduce-system-id-st__0', + 'testName' => __METHOD__.' with data set "te{{[0]|reduce(\'system\',\'id\')}}st"', + 'expectedOutput' => $baseTemplate.'te-0-reduce-system-id-st__0', ]; } }