From 9198cb183cfd32e807494633cd75c6017624886c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Tue, 8 Sep 2026 01:28:54 +0200 Subject: [PATCH] Document the extension as implemented The README covers installation, both configuration forms (behat.yml on Behat 3, behat.php on Behat 3 and 4), the options, the five step patterns that exist, and how to write custom steps. CHANGELOG starts the Unreleased section. --- CHANGELOG.md | 23 ++++++++ README.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0ff051e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,23 @@ +# CHANGELOG + +## [Unreleased] + +### Added + +- `PlaywrightExtension` registers a `PlaywrightManager` shared by the whole run, a context initializer for every `PlaywrightAwareContext`, and a listener that closes the scenario page after each scenario and the browser after the run. +- `RawPlaywrightContext::getPage()` opens one isolated page per scenario, in its own browser context. +- `ExpectationFailedException`, thrown by assertion steps. +- A screenshot named `failed--.png` is saved when a scenario fails (`auto_screenshot_on_failure`). +- Support for Behat 4.0.0-alpha1 and Symfony 8 components. + +### Changed + +- Requires PHP 8.2 or later and `playwright-php/playwright` 1.4 or later. +- Relative URLs resolve through Playwright's `baseURL` context option. +- `slow_mo` is an integer (milliseconds) instead of `slow_mo.delay`. + +### Removed + +- `browser_options`, which was accepted and never read. +- `BrowserNotStartedException`: a page is always available inside a scenario. +- The `@BeforeScenario` / `@AfterScenario` hooks on `PlaywrightContext`; the extension manages the lifecycle. diff --git a/README.md b/README.md index 8d0dda2..cf0af1a 100644 --- a/README.md +++ b/README.md @@ -9,29 +9,151 @@ # Playwright PHP for Behat -A Behat extension that drives a real browser through +A Behat extension that runs your scenarios in a real browser through [Playwright PHP](https://github.com/playwright-php/playwright). -## Status +Use it when feature files are the contract with your product owners and the +steps need a browser: Chromium, Firefox, or WebKit. The extension launches the +browser once per run and gives every scenario its own browser context, so +cookies and storage never leak between scenarios and no browser is relaunched. -Unreleased. The package installs and its test suite runs, but the extension -configuration is not yet connected to the Behat contexts, so a `behat.yml` -setup does not work end to end. Do not use it in an application yet. - -If you use Behat through Mink, use +If your suite already relies on Mink, use [playwright-mink](https://github.com/playwright-php/playwright-mink) instead: -it is released and supported. +it keeps the Mink API and swaps the driver. + +## Installation + +The extension requires PHP 8.2 or later, Behat 3.23 or later, and Playwright +PHP 1.4 or later. + +```bash +composer require --dev playwright-php/playwright-behat +vendor/bin/playwright-install --browsers +``` + +## Configuration + +Enable the extension and add the built-in context to a suite. With Behat 3.x, +in `behat.yml`: + +```yaml +default: + extensions: + Playwright\Behat\ServiceContainer\PlaywrightExtension: + base_url: 'http://localhost:8000' + suites: + web: + paths: ['%paths.base%/features'] + contexts: + - Playwright\Behat\Context\PlaywrightContext +``` + +Behat 4 drops YAML configuration. The PHP form below works on Behat 3.x and 4.x: + +```php +withProfile((new Profile('default')) + ->withExtension(new Extension(PlaywrightExtension::class, [ + 'base_url' => 'http://localhost:8000', + ])) + ->withSuite((new Suite('web')) + ->withPaths('%paths.base%/features') + ->withContexts(PlaywrightContext::class))); +``` -## Development +All options and their defaults: + +| Option | Default | Meaning | +|------------------------------|--------------------------------|------------------------------------------------------------| +| `browser` | `chromium` | `chromium`, `firefox`, or `webkit` | +| `headless` | `true` | Run without a visible window | +| `base_url` | `null` | Prefix for relative URLs passed to `goto()` | +| `timeout` | `30000` | Default timeout for actions and navigations, in ms | +| `slow_mo` | `0` | Delay between browser operations, in ms | +| `viewport` | `{width: 1280, height: 720}` | Viewport of every scenario page | +| `screenshot_dir` | `%paths.base%/var/screenshots` | Where named and failure screenshots go | +| `auto_screenshot_on_failure` | `true` | Save `failed--.png` when a scenario fails | + +## Usage + +The built-in `PlaywrightContext` provides these steps. Selectors are Playwright +selectors: CSS by default, plus `text=`, `role=` and the other engines. + +```gherkin +Feature: Login + Scenario: Sign in with valid credentials + Given I am on "/login" + When I fill "#email" with "user@example.com" + And I fill "#password" with "secret" + And I click on "button[type=submit]" + Then I should see "Dashboard" + And I take a screenshot named "after login" +``` + +| Step | Effect | +|---------------------------------------|-----------------------------------------------------| +| `Given I am on :url`, `When I go to :url` | Navigates; relative URLs resolve against `base_url` | +| `When I click on :selector` | Waits for the element, then clicks it | +| `When I fill :selector with :value` | Waits for the field, then fills it | +| `Then I should see :text` | Fails unless the page HTML contains the text | +| `When I take a screenshot named :name`| Saves `.png` under `screenshot_dir` | + +A failing step throws `Playwright\Behat\Exception\ExpectationFailedException`, +or the Playwright PHP exception for a timeout. + +## Custom steps + +Extend `RawPlaywrightContext` to write your own steps against the Playwright +PHP `Page`. The page is opened on first use and closed after the scenario: + +```php +getPage(); + $page->goto('/admin/login'); + $page->locator('#username')->fill('admin'); + $page->locator('#password')->fill('secret'); + $page->locator('[type="submit"]')->click(); + } +} +``` + +A context that cannot extend `RawPlaywrightContext` can implement +`Playwright\Behat\Context\PlaywrightAwareContext` instead: the extension calls +`setPlaywrightManager()` on it before the run, and +`PlaywrightManager::getPage()` returns the page of the current scenario. + +## Testing ```bash composer install vendor/bin/playwright-install --browsers -composer cs-check -composer sa -composer test +vendor/bin/phpunit ``` +The suite includes a real `behat` run against `tests/Fixtures`, including a +failing scenario that must leave a screenshot. Repository CI runs it on PHP +8.2, 8.3 and 8.4 against the latest Behat 3.x, plus one job on the lowest +supported dependencies and one on Behat 4.0.0-alpha1. + ## License -Released under the [MIT License](LICENSE). +Playwright PHP for Behat is released under the [MIT License](LICENSE).