rmb32 / scenario-runner
A small, generic Given/When/Then scenario execution engine โ Act/Arrange/Assert/Authenticate ports, no framework or transport opinions
Requires
- php: ^8.5
- ext-dom: *
- ext-ds: ^2.0
- php-ds/php-ds: ^2.0
Requires (Dev)
- deptrac/deptrac: ^4.7
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^12.0
- squizlabs/php_codesniffer: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-26 21:17:26 UTC
README
A small, generic Given/When/Then execution engine. Describe your acceptance scenarios as plain data โ areas of business, roles, stories, scenarios that arrange some facts, perform one action and assert some facts โ and Scenario Runner runs them and reports exactly what passed and failed. It has no framework, storage or transport opinions: you supply the domain logic by implementing a few interfaces.
Requirements
- PHP 8.5+,
ext-dom
Installation
composer require rmb32/scenario-runner
The ports you implement
| Port | Does |
|---|---|
Arrange | sets up one given fact's state |
Assert | answers whether one then fact now holds |
Act | performs the action, returns the actual outcome (Accepted / Rejected) |
Authenticate | establishes a role as the one performing a story |
ReadStorage / WriteStorage | the one piece of state Scenario Runner itself touches |
Each fact, action and role in your data names its own handler class. By default
it is built with new $className(). Give the builder a PortFactory to build
them any other way, such as from your application's container:
$tester = new AreaOfBusinessTesterBuilder(
ports: new ContainerPorts(), // implements PortFactory
storages: new MyStorageFactory(), // implements StorageFactory
)->build();
- With a
StorageFactory, every Scenario runs in a storage of its own, so the order Scenarios run in never matters. - A role is authenticated at the start of every Scenario it performs.
- A
PortFactorythat also implementsBeforeEachScenariois told before each Scenario begins: the place to empty a test database. - A Port that throws fails only its own Scenario. It is reported as crashed, with
where and why (
๐ฅ โฆ the Scenario crashed in Given: RuntimeException: โฆ), and every other Scenario still runs. - A Given or Then may use the same fact more than once, with different arguments; each use runs, in order.
Running scenarios
use Rmb32\ScenarioRunner\Api\Factory\AreaOfBusinessTesterBuilder;
use Rmb32\ScenarioRunner\Api\ValueObject\CliTestMessageFormatter;
$tester = new AreaOfBusinessTesterBuilder()->build();
$result = $tester->test($areaOfBusinessData, $storage, $storage);
$result->passed(); // bool
$formatter = new CliTestMessageFormatter();
echo $result->message($formatter); // coloured pass/fail report
$areaOfBusinessData is built from the AreaOfBusinessData /
RoleData / StoryData / ScenarioData value objects; $storage implements
both ReadStorage and WriteStorage.
Reporting
CliTestMessageFormatterโ ANSI-coloured terminal output.XmlTestReportโ a JUnit-style XML report most CI systems display natively.- Observer targets (
CliPrintTarget,SummaryTarget,XmlExportTarget,NdjsonExportTarget,CsvExportTarget) with filters (FailuresOnlyFilter,PassesOnlyFilter,RoleFilter,StoryFilter,ScenarioFilter) let you send the same result to several places, each with its own view. ImplementOutputSinkto send output somewhere new.
Used in Barn
This package is used in Barn. Learn about Barn. There, Scenario Bridge runs the scenarios captured in Barnspec through it, Port Generator writes the Port stubs, and Scenario Runner CLI scaffolds unit tests.
More docs
License
Proprietary. See LICENSE. Copyright (c) Roger Barnfather.