Quickstart
Install Pest Flow and run your first behaviour scenario with Pest.
This guide installs Pest Flow from Packagist, adds one feature test, and runs it with Pest. It assumes you already have a PHP project with Composer and Pest 5 installed.
Requirements
- PHP 8.4 or newer
- Pest 5
- Composer
Install
Run this command from your application directory:
composer require --dev maxiviper117/pest-flow
Composer installs Pest Flow as a development dependency and loads its DSL functions automatically. You do not need to add a Pest plugin bootstrap file.
Write your first scenario
Create tests/Feature/CheckoutFlowTest.php:
<?php
use function Pest\Flow\{feature, rule, scenario, given, when, then};
feature('Checkout', function (): void {
rule('Discounts reduce the order total', function (): void {
scenario('Applies a fixed discount', function (): void {
given('an order worth 120 dollars', function (): void {
$this->subtotal = 120;
});
when('a discount of 12 dollars is applied', function (): void {
$this->total = $this->subtotal - 12;
});
then('the total is 108 dollars', function (): void {
expect($this->total)->toBe(108);
});
});
});
});
The nesting gives the test a clear business context:
feature()groups tests for a capability.rule()groups scenarios that express a business rule.scenario()registers a normal Pest test.given(),when(), andthen()run their closures in declaration order inside that test.
The closures share Pest’s test object. In this example, $this->subtotal set in Given is available in the later steps. Use non-static closures when accessing $this.
Run the test
vendor/bin/pest tests/Feature/CheckoutFlowTest.php
Pest reports the scenario like any other test. Assertions, lifecycle hooks, and test failures continue to use Pest’s normal behavior.
To print the Feature, Rule, Scenario, and step hierarchy after the normal Pest output, add --flow:
vendor/bin/pest --flow tests/Feature/CheckoutFlowTest.php
Status symbols are colored when the terminal supports it. Color is disabled automatically when output is redirected.
Export behavior as JSON
To send a JSON document to stdout, add --flow-json. Pest suppresses its normal output in this mode
so stdout contains only JSON:
vendor/bin/pest --flow-json tests/Feature/CheckoutFlowTest.php
To save the document to a file and keep Pest’s normal output, pass a file name:
vendor/bin/pest --flow-json=flow.json tests/Feature/CheckoutFlowTest.php
The document includes a schema version, the feature and rule hierarchy, standalone scenarios, source locations, execution statuses, durations, and tags declared on each node. See the JSON export reference for the complete schema.
Tag and filter behaviours
Add tags directly to features, rules, or scenarios:
feature('Checkout', function (): void {
rule('Payment', function (): void {
scenario('charges a customer', function (): void {
// Given / When / Then steps...
})->tags('payments', 'critical');
})->tags('billing');
})->tags('checkout');
Feature and rule tags are inherited by descendant scenarios for filtering. Pest Flow uses Pest
groups, so select tagged scenarios with the existing --group option:
vendor/bin/pest --group=payments
Each node’s JSON tags array contains only tags declared directly on that node. See
tags and filtering for validation rules and more examples.
Generate living documentation
After a Pest run, generate a static HTML behaviour catalogue with:
vendor/bin/pest --flow-report
Pest writes build/pest-flow/index.html. Pass a directory to use another output location:
vendor/bin/pest --flow-report=docs/behaviour
The report includes navigation, counts, direct tags, source locations, and execution metadata. Unselected scenarios in a filtered run remain listed as pending. Their steps may be absent because Pest Flow records steps when a scenario runs. See living documentation for output details and the parallel execution limitation.
If something does not work
- A DSL function is undefined: check the
use function Pest\Flow\...import and runcomposer installafter adding the dependency. - Composer cannot find the package: check that the VCS repository was added to the application root and that PHP and Pest meet the requirements.
- A
rule()call is rejected: place it insidefeature(). - A step is rejected: call it inside a
scenario()definition, not directly in the test file or a feature callback.
See troubleshooting for the complete list of placement rules and errors. Continue with the first scenario walkthrough for a full example, or the DSL reference for every function.