Add Behat support - #194
Conversation
627010f to
1d91ba1
Compare
- `BrowserOptions` (readonly value object) — env-var-driven configuration
- `BrowserRegistry` — replaces the static state previously held by `LegacyExtension`
- `KernelBooter` interface + `Test/PhpUnitKernelBooter` (closure-fed, captures the trait's privileged scope)
- `BrowserFactory` — builds `KernelBrowser` / `PantherBrowser` from a booter
- `Artifact/{ArtifactSink, ArtifactCollector, EchoArtifactSink, FailureType}` — the lifecycle/artifact-capture logic extracted out of `LegacyExtension`
- `HasBrowser` trait: now ~95 lines, delegates to `BrowserFactory` with closures granting protected-static access
- `LegacyExtension` / `BootstrappedExtension`: thin adapters forwarding events to `ArtifactCollector`
- `BrowserExtension`: unchanged externally — same `phpunit.xml.dist` snippet works
- `BrowserExtension` — Behat `ServiceContainer` Extension wiring everything
- `Context/{BrowserAware, BrowserAwareTrait}` — drop-in analog of `HasBrowser`
- `Initializer/BrowserContextInitializer` — injects services via Behat's standard DI
- `EventListener/ArtifactListener` — Suite + Scenario events drive `ArtifactCollector`
- `Output/BehatOutputArtifactSink` — STDOUT-direct summary writer
- `Kernel/{KernelBooter implementations}` — `StandaloneKernelBooter` (env-var) and `SymfonyExtensionKernelBooter` (FoB), selected at compile time via class_exists; PantherClientFactory adapter to bypass Panther's protected statics
- `composer.json`: `behat/behat ^3.13|^4.0@dev` added to `require-dev`; both behat and FoB extension listed in suggest
- `tests/Behat/{behat.dist.php, behat.yml.dist, Context/BrowserContext.php, features/browser.feature}` — exercises the bridge end-to-end against the existing fixture kernel
- `README.md`: new "Using with Behat" section with context + config examples
Known caveat documented in the plan: `friends-of-behat/symfony-extension` doesn't yet support Symfony 8, so I could only end-to-end verify the `StandaloneKernelBooter` path. The `SymfonyExtensionKernelBooter` is code-complete and PHPStan-clean, but will need either a downgraded composer profile or a FoB release that supports Symfony 8 to verify in CI. The class is wired conditionally so it doesn't break consumers without FoB installed.
1d91ba1 to
a5617e9
Compare
|
@kbond I've tested this branch on a personal private project and it works :) Edit: I'ven't tested with Panther yet. |
|
I haven't forgotten about this @hhamon. I'm in the process of adding Playwright support, then I'm going to revisit this! |
|
yep, I'll review it as well, as soon as I got some time 👍 |
There was a problem hiding this comment.
hey @hhamon
it's pretty cool to enable this library in Behat!
really sorry to review this late. Moreover now, a lot of changes need to be done to support Playwright
Since Panther support is deprecated in this library, I think we should only focus on SF Kernel browser and Playwright. I also think it might simplify some stuff around booting the kernel/creating the bowser.
Because it implies a lot of changes, reviewing before Playwright is implemented causes too much friction. Any chance you rebase your PR, drop Panther support and implement Playwright support for Behat?
BTW, could you share some thoughts/explanations on some decisions you took please? that would definitely help with the review!
| * @param array<string, mixed> $kernelOptions | ||
| * @param array<string, mixed> $managerOptions | ||
| */ | ||
| public function createPantherBrowser(array $options = [], array $kernelOptions = [], array $managerOptions = []): PantherBrowser |
There was a problem hiding this comment.
since the recent updates, I think it would be OK not to provide an implementation of a Panther client, but maybe we can provide a PlaywrightClient ?
| { | ||
| $this->browserFactory = $factory; | ||
| $this->browserRegistry = $registry; | ||
| $this->browserKernelBooter = $booter; |
| * @param array<string, mixed> $options Kernel boot options | ||
| * @param array<string, mixed> $server Server parameters (REMOTE_ADDR, HTTPS, ...) | ||
| */ | ||
| public function createKernelBrowserClient(array $options = [], array $server = []): SymfonyKernelBrowser; |
There was a problem hiding this comment.
It feels strange to have both methods here: don't you think we couldn't do only two implementations: SymfonyKernelBrowserBooter and PlaywrightKernelBooter? maybe we can boot them independtly from the test context, they just need the kernel to be passed
NB: I know you needed to call PantherTestCase::createPantherdClient() which is protected, but that's not the case for Playwright. Thus I think all this "boot" phase could be simplified
|
@hhamon another thing: the PR is pretty massive, any chance that you split this PR in two smaller PRs? one with all the "boot" logic, the other one with Behat's extension and all? (maybe a third which handles the artifacts?) thanks! 🙏 |
|
@nikophil since the integration of Playwright support, this MR is no longer relevant. I've managed to update one of my project using Zenstruck Browser + Behat + Playwright more easily. So, I think, we should simply consider making support for Behat using Playwright. edit: thanks for the review btw :) |
|
maybe we could still ease browser's usage in Behat? (I mean with and without Playwright) |
|
@nikophil yeah that could be a good idea! |
Framework-agnostic core (
src/Browser/)BrowserOptions(readonly value object) — env-var-driven configurationBrowserRegistry— replaces the static state previously held byLegacyExtensionKernelBooterinterface +Test/PhpUnitKernelBooter(closure-fed, captures the trait's privileged scope)BrowserFactory— buildsKernelBrowser/PantherBrowserfrom a booterArtifact/{ArtifactSink, ArtifactCollector, EchoArtifactSink, FailureType}— the lifecycle/artifact-capture logic extracted out ofLegacyExtensionPHPUnit Decoupling
HasBrowsertrait: now ~95 lines, delegates toBrowserFactorywith closures granting protected-static accessLegacyExtension/BootstrappedExtension: thin adapters forwarding events toArtifactCollectorBrowserExtension: unchanged externally — samephpunit.xml.distsnippet worksBehat Bridge
BrowserExtension— BehatServiceContainerExtension wiring everythingContext/{BrowserAware, BrowserAwareTrait}— drop-in analog ofHasBrowserInitializer/BrowserContextInitializer— injects services via Behat's standard DIEventListener/ArtifactListener— Suite + Scenario events driveArtifactCollectorOutput/BehatOutputArtifactSink— STDOUT-direct summary writerKernel/{KernelBooter implementations}—StandaloneKernelBooter(env-var) andSymfonyExtensionKernelBooter(FoB), selected at compile time via class_exists; PantherClientFactory adapter to bypass Panther's protected staticsComposer Update
composer.json:behat/behat ^3.13|^4.0@devadded torequire-dev; both behat and FoB extension listed in suggesttests/Behat/{behat.dist.php, behat.yml.dist, Context/BrowserContext.php, features/browser.feature}— exercises the bridge end-to-end against the existing fixture kernelREADME.md: new "Using with Behat" section with context + config examplesKnown caveat documented in the plan:
friends-of-behat/symfony-extensiondoesn't yet support Symfony 8, so I could only end-to-end verify theStandaloneKernelBooterpath. TheSymfonyExtensionKernelBooteris code-complete and PHPStan-clean, but will need either a downgraded composer profile or a FoB release that supports Symfony 8 to verify in CI. The class is wired conditionally so it doesn't break consumers without FoB installed.Co-Authored with Claude Code