Skip to content
Pest Flow
Esc
↑↓navigate↵open⌘Jpreview
On this page

Behaviour registry

Inspect Pest Flow nodes, identifiers, source locations, and runtime timing.

Pest\Flow\FlowRegistry exposes the behaviour declarations loaded in the current PHP process. Use it from PHP code when you need to inspect the feature tree or the steps recorded while tests run.

Read the registry

use Pest\Flow\FlowRegistry;

$features = FlowRegistry::features();
$rules = FlowRegistry::rules();
$scenarios = FlowRegistry::scenarios();
$steps = FlowRegistry::steps();

Each method returns a list in declaration order:

Method Returns Contents
features() list<FeatureNode> Top-level feature declarations.
rules() list<RuleNode> All rules, flattened in feature and declaration order.
scenarios() list<ScenarioNode> All scenarios, including standalone scenarios.
steps() list<StepNode> Step declarations recorded by scenarios that have started, including steps skipped after a failure.

You can also walk the tree from a feature: FeatureNode::rules(), RuleNode::scenarios(), and ScenarioNode::steps() return each node’s children.

Node fields

The node objects expose their data as public properties. Feature, rule, and scenario tags are read with tags():

Node Properties Child access
FeatureNode id: string, name: string, source: SourceLocation; tags(): list<string> rules(): list<RuleNode>
RuleNode id: string, name: string, source: SourceLocation, feature: FeatureNode; tags(): list<string> scenarios(): list<ScenarioNode>
ScenarioNode id: string, name: string, source: SourceLocation, rule: ?RuleNode, status: ExecutionStatus, duration: ?float, exception: ?Throwable; tags(): list<string> steps(): list<StepNode>
StepNode id: string, type: StepType, description: string, source: SourceLocation, status: ExecutionStatus, duration: ?float, exception: ?Throwable None

SourceLocation provides file: string and line: int for the DSL declaration. For a feature, rule, or scenario, that is where its helper was called. For a step, it is the line where given(), when(), or then() was called.

Feature, rule, and scenario tags are available from each node’s tags() method. The method returns tags declared directly on that node; parent tags are inherited by child scenarios for Pest group filtering. See tags and filtering.

StepType is a backed enum with Given, When, and Then cases. Its string values are given, when, and then.

ExecutionStatus is a backed enum with Pending, Running, Passed, Failed, and Skipped cases. Its string values are pending, running, passed, failed, and skipped. A scenario or step that has not run remains Pending. A failing step stores its thrown Throwable and duration; Pest Flow rethrows that same exception so Pest retains its normal failure behavior. Steps declared after the failure are present with Skipped status and no duration or exception. A Pest skip exception marks the active step and scenario as skipped.

Durations are floating-point seconds measured with a monotonic high-resolution clock when available. A duration is null until execution completes. The scenario duration covers step declaration collection and execution; each step duration covers its callback only.

Runtime identifiers

Each node gets a path-like ID built from its name and its parent. For example:

Feature:  Contractor activation
Rule:     Only compliant contractors may activate
Scenario: Activates a compliant contractor

contractor-activation
contractor-activation/only-compliant-contractors-may-activate
contractor-activation/only-compliant-contractors-may-activate/activates-a-compliant-contractor

The ID slug lowercases ASCII letters, replaces each run of characters other than a-z and 0-9 with a hyphen, then trims hyphens from the ends. A name with no ASCII letters or digits uses node- followed by the first 12 characters of its SHA-256 hash.

If sibling nodes produce the same ID, Pest Flow appends -2, -3, and so on to keep each sibling unique. For example, two rules named Can activate under one feature receive can-activate and can-activate-2. Suffixes depend on declaration order. The same names declared in the same order produce the same IDs between runs.

Standalone scenarios have no feature or rule parent, so their IDs are based on the scenario name at the root.

When nodes are available

Feature, rule, and scenario nodes are registered as Pest loads the test definitions. Step nodes are created when their scenario runs, before any step callback executes. Pest Flow collects the declarations first so it can retain later steps as Skipped if an earlier callback fails.

// During test collection, a declared scenario is already in the registry.
$scenario = FlowRegistry::scenarios()[0];
$scenario->steps(); // empty until this scenario executes

// Inside a Then step, all declared steps are in the registry.
FlowRegistry::steps();

FlowRegistry::steps() aggregates recorded steps by scenario declaration order, with each scenario’s steps in declaration order. If a scenario runs more than once in the same process, its previous step list and execution metadata are cleared before the next run. If a step throws, its exception and duration remain visible, earlier steps remain Passed, and later declared steps are Skipped without being executed.

The registry is static and process-local. It does not aggregate data across separate PHP processes or provide a reset/reporting API. Parallel test workers therefore have separate registry state. A scenario that Pest never enters, including one skipped by a hook before its callback starts, remains Pending in the registry.

For a live example that inspects IDs and steps from a test, follow the registry walkthrough. See the DSL reference for how declarations are created.

Was this page helpful?