This repository has been archived by the owner on Jul 29, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[RFR] Inject store arguments in Behat hooks non step methods (#24)
* Inject store arguments in Behat hooks non step methods * Reorganize project structure * Try to decorate Behat services for Hook override * Successfully decorates HookableScenarioTester * Manage AfterScenario events * Fix AfterScenario feature * Add unit tests * Apply PHP-CS fixer * Update documentation * Fix review comments
- Loading branch information
1 parent
7e7a730
commit d8bfad9
Showing
14 changed files
with
525 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,16 @@ | ||
Feature: Scenario shared state | ||
In order to statefully test a | ||
suite of calls to a stateless | ||
system, I need a way to store the | ||
scenario state | ||
In order to statefully test a suite of calls to a stateless system, I need a way to store the scenario state | ||
|
||
Scenario: Scenario state should be shared between steps | ||
When I run "behat --no-colors features/monkey.feature" | ||
Then it should pass with: | ||
""" | ||
1 scenario (1 passed) | ||
""" | ||
""" | ||
1 scenario (1 passed) | ||
""" | ||
|
||
Scenario: Scenario state should be reseted between scenarios | ||
Scenario: Scenario state should be reset between scenarios | ||
When I run "behat --no-colors features/donkeys.feature" | ||
Then it should fail with: | ||
""" | ||
[Behat\Testwork\Argument\Exception\UnknownParameterValueException] | ||
""" | ||
""" | ||
[Behat\Testwork\Argument\Exception\UnknownParameterValueException] | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the ScenarioStateBehatExtension project. | ||
* | ||
* (c) Rodrigue Villetard <rodrigue.villetard@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher; | ||
|
||
use Behat\Testwork\Call\CallCenter; | ||
use Behat\Testwork\Call\CallResults; | ||
use Behat\Testwork\Environment\Call\EnvironmentCall; | ||
use Behat\Testwork\Hook\Call\HookCall; | ||
use Behat\Testwork\Hook\HookRepository; | ||
use Behat\Testwork\Hook\Scope\HookScope; | ||
use Doctrine\Common\Annotations\Reader; | ||
use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; | ||
use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; | ||
|
||
/** | ||
* @author Vincent Chalamon <vincent@les-tilleuls.coop> | ||
*/ | ||
class ScenarioStateHookDispatcher | ||
{ | ||
/** | ||
* @var HookRepository | ||
*/ | ||
private $repository; | ||
|
||
/** | ||
* @var CallCenter | ||
*/ | ||
private $callCenter; | ||
|
||
/** | ||
* @var Reader | ||
*/ | ||
private $reader; | ||
|
||
/** | ||
* @var ScenarioStateInitializer | ||
*/ | ||
private $store; | ||
|
||
/** | ||
* Initializes scenario state hook dispatcher. | ||
* | ||
* @param HookRepository $repository | ||
* @param CallCenter $callCenter | ||
* @param ScenarioStateInitializer $store | ||
* @param Reader $reader | ||
*/ | ||
public function __construct(HookRepository $repository, CallCenter $callCenter, ScenarioStateInitializer $store, Reader $reader) | ||
{ | ||
$this->repository = $repository; | ||
$this->callCenter = $callCenter; | ||
$this->reader = $reader; | ||
$this->store = $store; | ||
} | ||
|
||
/** | ||
* Dispatches hooks for a specified event. | ||
* | ||
* @param HookScope $scope | ||
* | ||
* @return CallResults | ||
*/ | ||
public function dispatchScopeHooks(HookScope $scope) | ||
{ | ||
$results = []; | ||
foreach ($this->repository->getScopeHooks($scope) as $hook) { | ||
/** @var \ReflectionMethod $function */ | ||
$function = $hook->getReflection(); | ||
|
||
// No `@ScenarioStateArgument` annotation found | ||
if (null === $this->reader->getMethodAnnotation($function, ScenarioStateArgument::class)) { | ||
$results[] = $this->callCenter->makeCall(new HookCall($scope, $hook)); | ||
continue; | ||
} | ||
|
||
$paramsKeys = array_map(function ($element) { | ||
return $element->name; | ||
}, $function->getParameters()); | ||
$store = $this->store->getStore(); | ||
$params = $arguments = []; | ||
|
||
// Prepare arguments from annotations | ||
/** @var ScenarioStateArgument[] $annotations */ | ||
$annotations = $this->reader->getMethodAnnotations($function); | ||
foreach ($annotations as $annotation) { | ||
if ($annotation instanceof ScenarioStateArgument && | ||
in_array($annotation->getArgument(), $paramsKeys) && | ||
$store->hasStateFragment($annotation->getName()) | ||
) { | ||
$params[$annotation->getArgument()] = $store->getStateFragment($annotation->getName()); | ||
} | ||
} | ||
|
||
// Manage `scope` argument | ||
foreach ($function->getParameters() as $parameter) { | ||
if (null !== $parameter->getClass() && get_class($scope) === $parameter->getClass()->getName()) { | ||
$arguments[$parameter->getName()] = $scope; | ||
} elseif (isset($params[$parameter->getName()])) { | ||
$arguments[$parameter->getName()] = $params[$parameter->getName()]; | ||
} | ||
} | ||
|
||
$results[] = $this->callCenter->makeCall(new EnvironmentCall($scope->getEnvironment(), $hook, $arguments)); | ||
} | ||
|
||
return new CallResults($results); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the ScenarioStateBehatExtension project. | ||
* | ||
* (c) Rodrigue Villetard <rodrigue.villetard@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Gorghoa\ScenarioStateBehatExtension\Hook\Tester; | ||
|
||
use Behat\Behat\Hook\Scope\AfterScenarioScope; | ||
use Behat\Behat\Hook\Scope\BeforeScenarioScope; | ||
use Behat\Behat\Tester\ScenarioTester; | ||
use Behat\Gherkin\Node\FeatureNode; | ||
use Behat\Gherkin\Node\ScenarioInterface as Scenario; | ||
use Behat\Testwork\Environment\Environment; | ||
use Behat\Testwork\Hook\Tester\Setup\HookedSetup; | ||
use Behat\Testwork\Hook\Tester\Setup\HookedTeardown; | ||
use Behat\Testwork\Tester\Result\TestResult; | ||
use Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher\ScenarioStateHookDispatcher; | ||
|
||
/** | ||
* @author Vincent Chalamon <vincent@les-tilleuls.coop> | ||
*/ | ||
final class ScenarioStateHookableScenarioTester implements ScenarioTester | ||
{ | ||
/** | ||
* @var ScenarioTester | ||
*/ | ||
private $baseTester; | ||
|
||
/** | ||
* @var ScenarioStateHookDispatcher | ||
*/ | ||
private $dispatcher; | ||
|
||
/** | ||
* @param ScenarioTester $baseTester | ||
* @param ScenarioStateHookDispatcher $dispatcher | ||
*/ | ||
public function __construct(ScenarioTester $baseTester, ScenarioStateHookDispatcher $dispatcher) | ||
{ | ||
$this->baseTester = $baseTester; | ||
$this->dispatcher = $dispatcher; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function setUp(Environment $env, FeatureNode $feature, Scenario $scenario, $skip) | ||
{ | ||
$setup = $this->baseTester->setUp($env, $feature, $scenario, true); | ||
|
||
if ($skip) { | ||
return $setup; | ||
} | ||
|
||
return new HookedSetup($setup, $this->dispatcher->dispatchScopeHooks(new BeforeScenarioScope($env, $feature, $scenario))); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function test(Environment $env, FeatureNode $feature, Scenario $scenario, $skip) | ||
{ | ||
return $this->baseTester->test($env, $feature, $scenario, $skip); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function tearDown(Environment $env, FeatureNode $feature, Scenario $scenario, $skip, TestResult $result) | ||
{ | ||
$teardown = $this->baseTester->tearDown($env, $feature, $scenario, true, $result); | ||
|
||
if ($skip) { | ||
return $teardown; | ||
} | ||
|
||
return new HookedTeardown($teardown, $this->dispatcher->dispatchScopeHooks(new AfterScenarioScope($env, $feature, $scenario, $result))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.