---
title: Quickstart
description: 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:

~~~sh
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
<?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()`, and `then()` 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

~~~sh
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`:

~~~sh
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:

~~~sh
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:

~~~sh
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](/pest-flow/json-export) for the complete schema.

## Tag and filter behaviours

Add tags directly to features, rules, or scenarios:

~~~php
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:

~~~sh
vendor/bin/pest --group=payments
~~~

Each node's JSON `tags` array contains only tags declared directly on that node. See
[tags and filtering](/pest-flow/tags) for validation rules and more examples.

## Generate living documentation

After a Pest run, generate a static HTML behaviour catalogue with:

~~~sh
vendor/bin/pest --flow-report
~~~

Pest writes `build/pest-flow/index.html`. Pass a directory to use another output location:

~~~sh
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](/pest-flow/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 run `composer install` after 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 inside `feature()`.
- **A step is rejected:** call it inside a `scenario()` definition, not directly in the test file or a feature callback.

See [troubleshooting](/pest-flow/troubleshooting) for the complete list of placement rules and errors. Continue with the [first scenario walkthrough](/pest-flow/walkthroughs/first-scenario) for a full example, or the [DSL reference](/pest-flow/api) for every function.
