Skip to content

Commit

Permalink
Merge branch '1.x' into 2.x
Browse files Browse the repository at this point in the history
* 1.x:
  minor: unpack Foundry 2 proxies (#160)
  feat: add `BROWSER_ALWAYS_START_WEBSERVER` env var (#156)
  feat: deprecate foundry integration
  minor: fix tests
  • Loading branch information
kbond committed Nov 5, 2024
2 parents 278ac33 + 28b7e1a commit 29d4fe6
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 100 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
39 changes: 22 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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)
;
```
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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

Expand Down
7 changes: 3 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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().",
Expand Down
33 changes: 22 additions & 11 deletions src/Browser/KernelBrowser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>
Expand Down Expand Up @@ -135,18 +136,23 @@ final public function withProfiling(): self
}

/**
* @param UserInterface|Proxy<UserInterface>|Factory<UserInterface> $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) {
Expand All @@ -159,7 +165,7 @@ public function actingAs(object $user, ?string $firewall = null): self
}

/**
* @param string|UserInterface|Proxy<UserInterface>|Factory<UserInterface>|null $as
* @param string|UserInterface|null $as
*
* @return static
*/
Expand All @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions src/Browser/Test/HasBrowser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/Browser/Test/LegacyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ private static function normalizeTestName(string $name): string
\preg_match('#^(?<test>[\w:\\\]+) with data set "(?<dataset>.*)"#', $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']);
Expand Down
5 changes: 0 additions & 5 deletions tests/Fixture/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion tests/HttpOptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
39 changes: 1 addition & 38 deletions tests/KernelBrowserAuthenticationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>
*/
final class KernelBrowserAuthenticationTest extends KernelTestCase
{
use Factories, HasBrowser;
use HasBrowser;

/**
* @test
Expand All @@ -41,54 +38,20 @@ 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
*/
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()
->actingAs($user)
->assertAuthenticated()
->assertAuthenticated($username)
->assertAuthenticated($user)
->assertAuthenticated($factory)
->assertAuthenticated($proxy)
->visit('/user')
->assertAuthenticated()
->assertAuthenticated($username)
Expand Down
46 changes: 23 additions & 23 deletions tests/NormalizationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -55,49 +55,49 @@ 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,
];
}

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',
];
}
}

0 comments on commit 29d4fe6

Please sign in to comment.