Add more sanity checks
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
Feature: Context constructor dependency injection compatibility
|
||||||
|
|
||||||
|
Scenario: Using context consturctor dependency injection
|
||||||
|
Given a working Symfony application with SymfonyExtension configured
|
||||||
|
And a Behat configuration containing:
|
||||||
|
"""
|
||||||
|
default:
|
||||||
|
suites:
|
||||||
|
default:
|
||||||
|
contexts:
|
||||||
|
- App\Tests\SomeContext:
|
||||||
|
- "@App\\Foo"
|
||||||
|
|
||||||
|
services:
|
||||||
|
App\Foo: ~
|
||||||
|
"""
|
||||||
|
And a class file "src/Foo.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
final class Foo
|
||||||
|
{
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then it should pass
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use App\Foo;
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
public function __construct(Foo $foo)
|
||||||
|
{
|
||||||
|
$this->foo = $foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @Then it should pass */
|
||||||
|
public function itShouldPass(): void
|
||||||
|
{
|
||||||
|
assert($this->foo instanceof Foo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
@@ -13,9 +13,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FriendsOfBehat\SymfonyExtension\Context\Environment\Handler;
|
namespace FriendsOfBehat\SymfonyExtension\Context\Environment\Handler;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Argument\ArgumentResolverFactory;
|
||||||
|
use Behat\Behat\Context\Argument\NullFactory;
|
||||||
|
use Behat\Behat\Context\Argument\SuiteScopedResolverFactory;
|
||||||
|
use Behat\Behat\Context\Argument\SuiteScopedResolverFactoryAdapter;
|
||||||
use Behat\Behat\Context\Context;
|
use Behat\Behat\Context\Context;
|
||||||
use Behat\Behat\Context\ContextClass\ClassResolver;
|
use Behat\Behat\Context\ContextClass\ClassResolver;
|
||||||
use Behat\Behat\Context\Initializer\ContextInitializer;
|
use Behat\Behat\Context\ContextFactory;
|
||||||
use Behat\Testwork\Environment\Environment;
|
use Behat\Testwork\Environment\Environment;
|
||||||
use Behat\Testwork\Environment\Exception\EnvironmentIsolationException;
|
use Behat\Testwork\Environment\Exception\EnvironmentIsolationException;
|
||||||
use Behat\Testwork\Environment\Handler\EnvironmentHandler;
|
use Behat\Testwork\Environment\Handler\EnvironmentHandler;
|
||||||
@@ -32,15 +36,29 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
/** @var KernelInterface */
|
/** @var KernelInterface */
|
||||||
private $symfonyKernel;
|
private $symfonyKernel;
|
||||||
|
|
||||||
/** @var ContextInitializer[] */
|
|
||||||
private $contextInitializers = [];
|
|
||||||
|
|
||||||
/** @var ClassResolver[] */
|
/** @var ClassResolver[] */
|
||||||
private $classResolvers = [];
|
private $classResolvers = [];
|
||||||
|
|
||||||
public function __construct(KernelInterface $symfonyKernel)
|
/** @var ContextFactory */
|
||||||
|
private $contextFactory;
|
||||||
|
|
||||||
|
/** @var ArgumentResolverFactory */
|
||||||
|
private $resolverFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ArgumentResolverFactory|SuiteScopedResolverFactory $resolverFactory
|
||||||
|
*/
|
||||||
|
public function __construct(KernelInterface $symfonyKernel, ContextFactory $factory, $resolverFactory = null)
|
||||||
{
|
{
|
||||||
$this->symfonyKernel = $symfonyKernel;
|
$this->symfonyKernel = $symfonyKernel;
|
||||||
|
|
||||||
|
$this->contextFactory = $factory;
|
||||||
|
|
||||||
|
if ($resolverFactory && !$resolverFactory instanceof ArgumentResolverFactory) {
|
||||||
|
$resolverFactory = new SuiteScopedResolverFactoryAdapter($resolverFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resolverFactory = $resolverFactory ?: new NullFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function supportsSuite(Suite $suite): bool
|
public function supportsSuite(Suite $suite): bool
|
||||||
@@ -51,8 +69,8 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
public function buildEnvironment(Suite $suite): Environment
|
public function buildEnvironment(Suite $suite): Environment
|
||||||
{
|
{
|
||||||
$environment = new UninitialisedContextServiceEnvironment($suite);
|
$environment = new UninitialisedContextServiceEnvironment($suite);
|
||||||
foreach ($this->getSuiteContextsServices($suite) as $contextId) {
|
foreach ($this->getSuiteContextsServices($suite) as [$contextId, $contextArguments]) {
|
||||||
$environment->registerContextService($contextId, $this->getContextClass($contextId));
|
$environment->registerContextService($contextId, $this->getContextClass($contextId), $contextArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $environment;
|
return $environment;
|
||||||
@@ -73,28 +91,24 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
$this->assertEnvironmentCanBeIsolated($uninitializedEnvironment, $testSubject);
|
$this->assertEnvironmentCanBeIsolated($uninitializedEnvironment, $testSubject);
|
||||||
|
|
||||||
$environment = new InitialisedContextServiceEnvironment($uninitializedEnvironment->getSuite());
|
$environment = new InitialisedContextServiceEnvironment($uninitializedEnvironment->getSuite());
|
||||||
foreach ($uninitializedEnvironment->getContextServices() as $contextId) {
|
$resolvers = $this->resolverFactory->createArgumentResolvers($environment);
|
||||||
|
|
||||||
|
foreach ($uninitializedEnvironment->getContextServicesWithArguments() as $contextId => $arguments) {
|
||||||
/** @var Context $context */
|
/** @var Context $context */
|
||||||
$context = $this->getContext($contextId);
|
$context = $this->getContext($contextId, $arguments, $resolvers);
|
||||||
$this->initializeInstance($context);
|
|
||||||
$environment->registerContext($context);
|
$environment->registerContext($context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $environment;
|
return $environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerContextInitializer(ContextInitializer $contextInitializer): void
|
|
||||||
{
|
|
||||||
$this->contextInitializers[] = $contextInitializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerClassResolver(ClassResolver $classResolver): void
|
public function registerClassResolver(ClassResolver $classResolver): void
|
||||||
{
|
{
|
||||||
$this->classResolvers[] = $classResolver;
|
$this->classResolvers[] = $classResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return array[]
|
||||||
*
|
*
|
||||||
* @throws SuiteConfigurationException If "contexts" setting is not an array
|
* @throws SuiteConfigurationException If "contexts" setting is not an array
|
||||||
*/
|
*/
|
||||||
@@ -110,7 +124,20 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
), $suite->getName());
|
), $suite->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $contextsServices;
|
return array_map(
|
||||||
|
function ($context): array {
|
||||||
|
$class = $context;
|
||||||
|
$arguments = [];
|
||||||
|
|
||||||
|
if (is_array($context)) {
|
||||||
|
$class = current(array_keys($context));
|
||||||
|
$arguments = $context[$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$class, $arguments];
|
||||||
|
},
|
||||||
|
$contextsServices
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,13 +154,6 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function initializeInstance(Context $context): void
|
|
||||||
{
|
|
||||||
foreach ($this->contextInitializers as $initializer) {
|
|
||||||
$initializer->initializeContext($context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function resolveContextId(string $contextId): string
|
private function resolveContextId(string $contextId): string
|
||||||
{
|
{
|
||||||
foreach ($this->classResolvers as $resolver) {
|
foreach ($this->classResolvers as $resolver) {
|
||||||
@@ -162,7 +182,7 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
throw new \DomainException(sprintf('There is no service or class "%s".', $contextId));
|
throw new \DomainException(sprintf('There is no service or class "%s".', $contextId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getContext(string $contextId): Context
|
private function getContext(string $contextId, array $arguments = [], array $resolvers = []): Context
|
||||||
{
|
{
|
||||||
$contextId = $this->resolveContextId($contextId);
|
$contextId = $this->resolveContextId($contextId);
|
||||||
|
|
||||||
@@ -171,7 +191,7 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
if ($this->getContainer()->has($contextId)) {
|
if ($this->getContainer()->has($contextId)) {
|
||||||
$context = $this->getContainer()->get($contextId);
|
$context = $this->getContainer()->get($contextId);
|
||||||
} elseif (class_exists($class)) {
|
} elseif (class_exists($class)) {
|
||||||
$context = new $class();
|
$context = $this->contextFactory->createContext($class, $arguments, $resolvers);
|
||||||
} else {
|
} else {
|
||||||
throw new \DomainException(sprintf('There is no service or class "%s".', $contextId));
|
throw new \DomainException(sprintf('There is no service or class "%s".', $contextId));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,12 @@ final class UninitialisedContextServiceEnvironment extends StaticEnvironment imp
|
|||||||
/** @var string[] */
|
/** @var string[] */
|
||||||
private $contextServices = [];
|
private $contextServices = [];
|
||||||
|
|
||||||
public function registerContextService(string $serviceId, string $serviceClass): void
|
public function registerContextService(string $serviceId, string $serviceClass, array $arguments = []): void
|
||||||
{
|
{
|
||||||
$this->contextServices[$serviceId] = $serviceClass;
|
$this->contextServices[$serviceId] = [
|
||||||
|
'class' => $serviceClass,
|
||||||
|
'arguments' => $arguments,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContextServices(): array
|
public function getContextServices(): array
|
||||||
@@ -41,11 +44,20 @@ final class UninitialisedContextServiceEnvironment extends StaticEnvironment imp
|
|||||||
|
|
||||||
public function getContextClasses(): array
|
public function getContextClasses(): array
|
||||||
{
|
{
|
||||||
return array_values($this->contextServices);
|
return array_map(function (array $contextDetails): string {
|
||||||
|
return $contextDetails['class'];
|
||||||
|
}, $this->contextServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasContextClass($class): bool
|
public function hasContextClass($class): bool
|
||||||
{
|
{
|
||||||
return in_array($class, $this->contextServices, true);
|
return in_array($class, $this->getContextClasses(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContextServicesWithArguments(): iterable
|
||||||
|
{
|
||||||
|
foreach ($this->contextServices as $contextDetails) {
|
||||||
|
yield $contextDetails['class'] => $contextDetails['arguments'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,8 @@ final class SymfonyExtension implements Extension
|
|||||||
{
|
{
|
||||||
$definition = new Definition(ContextServiceEnvironmentHandler::class, [
|
$definition = new Definition(ContextServiceEnvironmentHandler::class, [
|
||||||
new Reference(self::KERNEL_ID),
|
new Reference(self::KERNEL_ID),
|
||||||
|
new Reference(ContextExtension::FACTORY_ID),
|
||||||
|
new Reference(ContextExtension::AGGREGATE_RESOLVER_FACTORY_ID)
|
||||||
]);
|
]);
|
||||||
$definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]);
|
$definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]);
|
||||||
|
|
||||||
@@ -250,10 +252,6 @@ final class SymfonyExtension implements Extension
|
|||||||
{
|
{
|
||||||
$definition = $container->findDefinition('fob_symfony.environment_handler.context_service');
|
$definition = $container->findDefinition('fob_symfony.environment_handler.context_service');
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds(ContextExtension::INITIALIZER_TAG) as $serviceId => $tags) {
|
|
||||||
$definition->addMethodCall('registerContextInitializer', [$container->getDefinition($serviceId)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds(ContextExtension::CLASS_RESOLVER_TAG) as $serviceId => $tags) {
|
foreach ($container->findTaggedServiceIds(ContextExtension::CLASS_RESOLVER_TAG) as $serviceId => $tags) {
|
||||||
$definition->addMethodCall('registerClassResolver', [$container->getDefinition($serviceId)]);
|
$definition->addMethodCall('registerClassResolver', [$container->getDefinition($serviceId)]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user