From 776af6cc38f86000513b1d3c4cdd2cfcdc18f4a8 Mon Sep 17 00:00:00 2001 From: Kamil Kokot Date: Sat, 4 Apr 2020 15:13:01 +0200 Subject: [PATCH 1/3] Describe accessing driver's service container --- ...ccessing_drivers_service_container.feature | 105 ++++++++++++++++++ tests/Behat/Context/TestContext.php | 77 +++++++++++-- 2 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 features/mink_integration/accessing_drivers_service_container.feature diff --git a/features/mink_integration/accessing_drivers_service_container.feature b/features/mink_integration/accessing_drivers_service_container.feature new file mode 100644 index 0000000..9bbf91c --- /dev/null +++ b/features/mink_integration/accessing_drivers_service_container.feature @@ -0,0 +1,105 @@ +Feature: Accessing driver's service container + + Background: + Given a working Symfony application with SymfonyExtension configured + And a Behat configuration containing: + """ + default: + extensions: + Behat\MinkExtension: + base_url: "http://localhost:8080/" + default_session: symfony + sessions: + symfony: + symfony: ~ + suites: + default: + contexts: + - App\Tests\SomeContext + """ + And a feature file containing: + """ + Feature: + Scenario: + Given the counter service is zeroed + When I visit the page "/hello-world" + Then the counter service should return 1 + + """ + And a context file "tests/SomeContext.php" containing: + """ + mink = $mink; + $this->container = $container; + } + + /** @Given the counter service is zeroed */ + public function counterServiceIsZeroed(): void + { + assert(0 === $this->getCounterService()->get()); + } + + /** @When I visit the page :page */ + public function visitPage(string $page): void + { + $this->mink->getSession()->visit($page); + } + + /** @Then the counter service should return :number */ + public function counterServiceShouldReturn(int $number): void + { + assert($number === $this->getCounterService()->get()); + } + + private function getCounterService(): Counter + { + return $this->container + ->get('behat.service_container') + ->get('fob_symfony.driver_kernel') + ->getContainer() + ->get('test.service_container') + ->get('App\Counter') + ; + } + } + """ + + Scenario: Injecting Mink serivce + Given a YAML services file containing: + """ + services: + App\Tests\SomeContext: + public: true + arguments: + - '@behat.mink' + - '@service_container' + """ + When I run Behat + Then it should pass + + Scenario: Autowiring and autoconfiguring Mink service + Given a YAML services file containing: + """ + services: + _defaults: + autowire: true + autoconfigure: true + + App\Tests\SomeContext: ~ + """ + When I run Behat + Then it should pass diff --git a/tests/Behat/Context/TestContext.php b/tests/Behat/Context/TestContext.php index a7f56fc..5c2ed64 100644 --- a/tests/Behat/Context/TestContext.php +++ b/tests/Behat/Context/TestContext.php @@ -92,12 +92,13 @@ class: App\Kernel $this->thereIsFile('src/Kernel.php', <<<'CON' 'Pigeon', ]); + $loader->load(__DIR__ . '/../config/default.yaml'); $loader->load(__DIR__ . '/../config/services.yaml'); } - protected function configureRoutes(RouteCollectionBuilder $routes) + protected function configureRoutes(RouteCollectionBuilder $routes): void + { + $routes->add('/hello-world', 'App\Controller:helloWorld'); + } +} +CON + ); + + $this->thereIsFile('src/Controller.php', <<<'CON' +counter = $counter; + } + + public function helloWorld(): Response + { + $this->counter->increase(); + + return new Response('Hello world!'); + } +} +CON + ); + + $this->thereIsFile('src/Counter.php', <<<'CON' +add('/hello-world', 'kernel:helloWorld'); + $this->counter++; + } + + public function get(): int + { + return $this->counter; } } CON ); + $this->thereIsFile('config/default.yaml', <<<'YML' +services: + App\Controller: + arguments: + - '@App\Counter' + public: true + + App\Counter: + public: false +YML + ); + $this->thereIsFile('config/services.yaml', ''); } From b05304858c9fba6a64aeef0ea6d9a195305a5297 Mon Sep 17 00:00:00 2001 From: Kamil Kokot Date: Sat, 4 Apr 2020 15:26:02 +0200 Subject: [PATCH 2/3] Introduce a service in the test application that exposes driver's service container --- ...ccessing_drivers_service_container.feature | 20 ++++++--------- ...riendsOfBehatSymfonyExtensionExtension.php | 25 +++++++++++++++++++ src/ServiceContainer/SymfonyExtension.php | 2 +- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/features/mink_integration/accessing_drivers_service_container.feature b/features/mink_integration/accessing_drivers_service_container.feature index 9bbf91c..f923ebb 100644 --- a/features/mink_integration/accessing_drivers_service_container.feature +++ b/features/mink_integration/accessing_drivers_service_container.feature @@ -39,12 +39,12 @@ Feature: Accessing driver's service container final class SomeContext implements Context { private $mink; - private $container; + private $driverContainer; - public function __construct(Mink $mink, ContainerInterface $container) + public function __construct(Mink $mink, ContainerInterface $driverContainer) { $this->mink = $mink; - $this->container = $container; + $this->driverContainer = $driverContainer; } /** @Given the counter service is zeroed */ @@ -67,18 +67,12 @@ Feature: Accessing driver's service container private function getCounterService(): Counter { - return $this->container - ->get('behat.service_container') - ->get('fob_symfony.driver_kernel') - ->getContainer() - ->get('test.service_container') - ->get('App\Counter') - ; + return $this->driverContainer->get('App\Counter'); } } """ - Scenario: Injecting Mink serivce + Scenario: Accessing a service from driver's service container (manually injected dependencies) Given a YAML services file containing: """ services: @@ -86,12 +80,12 @@ Feature: Accessing driver's service container public: true arguments: - '@behat.mink' - - '@service_container' + - '@behat.driver.service_container' """ When I run Behat Then it should pass - Scenario: Autowiring and autoconfiguring Mink service + Scenario: Accessing a service from driver's service container (autowired & autoconfigured dependencies) Given a YAML services file containing: """ services: diff --git a/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php b/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php index abfd109..c014a41 100644 --- a/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php +++ b/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php @@ -8,6 +8,7 @@ use Behat\Mink\Mink; use Behat\Mink\Session; use FriendsOfBehat\SymfonyExtension\Mink\MinkParameters; +use FriendsOfBehat\SymfonyExtension\ServiceContainer\SymfonyExtension; use Symfony\Component\BrowserKit\Client; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -15,6 +16,8 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpKernel\KernelInterface; final class FriendsOfBehatSymfonyExtensionExtension extends Extension implements CompilerPassInterface { @@ -22,6 +25,7 @@ public function load(array $configs, ContainerBuilder $container): void { $this->provideMinkIntegration($container); $this->registerBehatContainer($container); + $this->registerDriverBehatContainer($container); $container->registerForAutoconfiguration(Context::class)->addTag('fob.context'); } @@ -47,6 +51,27 @@ private function registerBehatContainer(ContainerBuilder $container): void $container->setDefinition('behat.service_container', $behatServiceContainerDefinition); } + private function registerDriverBehatContainer(ContainerBuilder $container): void + { + $driverKernelDefinition = new Definition(KernelInterface::class, [SymfonyExtension::DRIVER_KERNEL_ID]); + $driverKernelDefinition->setFactory([new Reference('behat.service_container'), 'get']); + $driverKernelDefinition->setPublic(true); + $driverKernelDefinition->setLazy(true); + + $driverServiceContainerDefinition = new Definition(ContainerInterface::class); + $driverServiceContainerDefinition->setFactory([$driverKernelDefinition, 'getContainer']); + $driverServiceContainerDefinition->setPublic(true); + $driverServiceContainerDefinition->setLazy(true); + + $driverTestServiceContainerDefinition = new Definition(ContainerInterface::class, ['test.service_container']); + $driverTestServiceContainerDefinition->setFactory([$driverServiceContainerDefinition, 'get']); + $driverTestServiceContainerDefinition->setPublic(true); + $driverTestServiceContainerDefinition->setLazy(true); + + $container->setDefinition('behat.driver.service_container', $driverTestServiceContainerDefinition); + $container->registerAliasForArgument('behat.driver.service_container', ContainerInterface::class, 'driver container'); + } + private function provideBrowserKitIntegration(ContainerBuilder $container): void { if (!class_exists(Client::class) || !$container->has('test.client')) { diff --git a/src/ServiceContainer/SymfonyExtension.php b/src/ServiceContainer/SymfonyExtension.php index f0d920c..d8e0565 100644 --- a/src/ServiceContainer/SymfonyExtension.php +++ b/src/ServiceContainer/SymfonyExtension.php @@ -34,7 +34,7 @@ final class SymfonyExtension implements Extension * Kernel used by Symfony driver to isolate web container from contexts' container. * Container is rebuilt before every request. */ - private const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel'; + public const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel'; /** @var bool */ private $minkExtensionFound = false; From e94285dc0ba4d13b07b018d6e953c9a6f79d300d Mon Sep 17 00:00:00 2001 From: Kamil Kokot Date: Sat, 4 Apr 2020 15:28:13 +0200 Subject: [PATCH 3/3] Fix coding standard --- ...ccessing_drivers_service_container.feature | 31 +++++++++---------- ...riendsOfBehatSymfonyExtensionExtension.php | 1 - 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/features/mink_integration/accessing_drivers_service_container.feature b/features/mink_integration/accessing_drivers_service_container.feature index f923ebb..44bb5c2 100644 --- a/features/mink_integration/accessing_drivers_service_container.feature +++ b/features/mink_integration/accessing_drivers_service_container.feature @@ -24,7 +24,6 @@ Feature: Accessing driver's service container Given the counter service is zeroed When I visit the page "/hello-world" Then the counter service should return 1 - """ And a context file "tests/SomeContext.php" containing: """ @@ -74,26 +73,26 @@ Feature: Accessing driver's service container Scenario: Accessing a service from driver's service container (manually injected dependencies) Given a YAML services file containing: - """ - services: - App\Tests\SomeContext: - public: true - arguments: - - '@behat.mink' - - '@behat.driver.service_container' - """ + """ + services: + App\Tests\SomeContext: + public: true + arguments: + - '@behat.mink' + - '@behat.driver.service_container' + """ When I run Behat Then it should pass Scenario: Accessing a service from driver's service container (autowired & autoconfigured dependencies) Given a YAML services file containing: - """ - services: - _defaults: - autowire: true - autoconfigure: true + """ + services: + _defaults: + autowire: true + autoconfigure: true - App\Tests\SomeContext: ~ - """ + App\Tests\SomeContext: ~ + """ When I run Behat Then it should pass diff --git a/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php b/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php index c014a41..cb8c4ff 100644 --- a/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php +++ b/src/Bundle/DependencyInjection/FriendsOfBehatSymfonyExtensionExtension.php @@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelInterface; final class FriendsOfBehatSymfonyExtensionExtension extends Extension implements CompilerPassInterface