Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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-<scenario>-<line>.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.
148 changes: 135 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<?php
// behat.php

use Behat\Config\Config;
use Behat\Config\Extension;
use Behat\Config\Profile;
use Behat\Config\Suite;
use Playwright\Behat\Context\PlaywrightContext;
use Playwright\Behat\ServiceContainer\PlaywrightExtension;

return (new Config())
->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-<scenario>-<line>.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 `<slug>.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
<?php

use Behat\Step\When;
use Playwright\Behat\Context\RawPlaywrightContext;

final class AdminContext extends RawPlaywrightContext
{
#[When('I sign in as an administrator')]
public function signInAsAdministrator(): void
{
$page = $this->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).
Loading