refactor #42 Acceptance tests for core functionalities (bartoszpietrzak1994, pamil)
This PR was merged into the 2.0-dev branch. Discussion ---------- Commits -------742d3358b5Injected parameter test POC7250dfca76Get bare Behat scenario running11f5a326b3Test injecting parametersd4efe9a6dfSimplify services definition in Behat9cede4d612Test injecting servicesd5fcb25ef2Test autowiring contextsb4bcbb1233Test autowired & autoconfigured contextsc8b0cbb205Test isolating contexts6061eaaf62Test Mink integration05f4fe789fApply coding standard fixes4405596ca1Make PHPStan passing85796e2fefFix build on Symfony 3.4
This commit is contained in:
133
features/autowiring_contexts.feature
Normal file
133
features/autowiring_contexts.feature
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
Feature: Autowiring contexts
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a working Symfony application with SymfonyExtension configured
|
||||||
|
And a Behat configuration containing:
|
||||||
|
"""
|
||||||
|
default:
|
||||||
|
suites:
|
||||||
|
default:
|
||||||
|
contexts:
|
||||||
|
- App\Tests\SomeContext
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Autowiring a context with a service
|
||||||
|
Given a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then the container should be passed
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
public function __construct(?ContainerInterface $container = null) { $this->container = $container; }
|
||||||
|
|
||||||
|
/** @Then the container should be passed */
|
||||||
|
public function containerShouldBePassed(): void
|
||||||
|
{
|
||||||
|
assert(is_object($this->container));
|
||||||
|
assert($this->container instanceof ContainerInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
public: true
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
|
|
||||||
|
Scenario: Autowiring a context with a binding
|
||||||
|
Given a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then the passed argument should be "KrzysztofKrawczyk"
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $argument;
|
||||||
|
|
||||||
|
public function __construct(?string $argument = null) { $this->argument = $argument; }
|
||||||
|
|
||||||
|
/** @Then the passed argument should be :expected */
|
||||||
|
public function passedArgumentShouldBe(string $expected): void { assert($this->argument === $expected); }
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
bind:
|
||||||
|
$argument: KrzysztofKrawczyk
|
||||||
|
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
public: true
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
|
|
||||||
|
Scenario: Autowiring and autoconfiguring context based on prototype
|
||||||
|
Given a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then the container should be passed
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
public function __construct(?ContainerInterface $container = null) { $this->container = $container; }
|
||||||
|
|
||||||
|
/** @Then the container should be passed */
|
||||||
|
public function containerShouldBePassed(): void
|
||||||
|
{
|
||||||
|
assert(is_object($this->container));
|
||||||
|
assert($this->container instanceof ContainerInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
App\Tests\:
|
||||||
|
resource: '../tests/*'
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
61
features/injecting_parameters_into_context.feature
Normal file
61
features/injecting_parameters_into_context.feature
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
Feature: Injecting parameters into context
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a working Symfony application with SymfonyExtension configured
|
||||||
|
And a Behat configuration containing:
|
||||||
|
"""
|
||||||
|
default:
|
||||||
|
suites:
|
||||||
|
default:
|
||||||
|
contexts:
|
||||||
|
- App\Tests\SomeContext
|
||||||
|
"""
|
||||||
|
And a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then the passed parameter should be "test"
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $parameter;
|
||||||
|
|
||||||
|
public function __construct(?string $parameter = null) { $this->parameter = $parameter; }
|
||||||
|
|
||||||
|
/** @Then the passed parameter should be :expected */
|
||||||
|
public function parameterShouldBe(string $expected): void { assert($this->parameter === $expected); }
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Injecting a parameter into a context explicitly set as public
|
||||||
|
Given a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
public: true
|
||||||
|
arguments:
|
||||||
|
- "%kernel.environment%"
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
|
|
||||||
|
Scenario: Injecting a parameter into an autoconfigured context
|
||||||
|
Given a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
arguments:
|
||||||
|
- "%kernel.environment%"
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
65
features/injecting_services_into_context.feature
Normal file
65
features/injecting_services_into_context.feature
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
Feature: Injecting services into context
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a working Symfony application with SymfonyExtension configured
|
||||||
|
And a Behat configuration containing:
|
||||||
|
"""
|
||||||
|
default:
|
||||||
|
suites:
|
||||||
|
default:
|
||||||
|
contexts:
|
||||||
|
- App\Tests\SomeContext
|
||||||
|
"""
|
||||||
|
And a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then the passed service should be an instance of "\Psr\Container\ContainerInterface"
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $service;
|
||||||
|
|
||||||
|
public function __construct($service = null) { $this->service = $service; }
|
||||||
|
|
||||||
|
/** @Then the passed service should be an instance of :expected */
|
||||||
|
public function serviceShouldBe(string $expected): void
|
||||||
|
{
|
||||||
|
assert(is_object($this->service));
|
||||||
|
assert($this->service instanceof $expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Injecting a service into a context explicitly set as public
|
||||||
|
Given a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
public: true
|
||||||
|
arguments:
|
||||||
|
- "@service_container"
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
|
|
||||||
|
Scenario: Injecting a service into an autoconfigured context
|
||||||
|
Given a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
arguments:
|
||||||
|
- "@service_container"
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
54
features/isolating_contexts.feature
Normal file
54
features/isolating_contexts.feature
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
Feature: Isolating contexts
|
||||||
|
|
||||||
|
Scenario: Keeping contexts isolated between scenarios
|
||||||
|
Given a working Symfony application with SymfonyExtension configured
|
||||||
|
And a Behat configuration containing:
|
||||||
|
"""
|
||||||
|
default:
|
||||||
|
suites:
|
||||||
|
default:
|
||||||
|
contexts:
|
||||||
|
- App\Tests\SomeContext
|
||||||
|
"""
|
||||||
|
And a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario: First scenario
|
||||||
|
Then the property should be "shit happens"
|
||||||
|
|
||||||
|
Scenario: Second scenario
|
||||||
|
When I change the property to "shit does not happen"
|
||||||
|
Then the property should be "shit does not happen"
|
||||||
|
|
||||||
|
Scenario: Third scenario
|
||||||
|
Then the property should be "shit happens"
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $property = 'shit happens';
|
||||||
|
|
||||||
|
public function __construct(?ContainerInterface $container = null) { $this->container = $container; }
|
||||||
|
|
||||||
|
/** @When I change the property to :value */
|
||||||
|
public function changeProperty(string $value): void { $this->property = $value; }
|
||||||
|
|
||||||
|
/** @Then the property should be :expected*/
|
||||||
|
public function propertyShouldBe(string $expected): void { assert($this->property === $expected); }
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
public: true
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
107
features/mink_integration.feature
Normal file
107
features/mink_integration.feature
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
Feature: Mink integration
|
||||||
|
|
||||||
|
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:
|
||||||
|
When I visit the page "/hello-world"
|
||||||
|
Then I should see "Hello world!" on the page
|
||||||
|
And the base url from Mink parameters should be "http://localhost:8080/"
|
||||||
|
|
||||||
|
# Doubling the scenario to account for some weird error connected to Mink's session
|
||||||
|
Scenario:
|
||||||
|
When I visit the page "/hello-world"
|
||||||
|
Then I should see "Hello world!" on the page
|
||||||
|
And the base url from Mink parameters should be "http://localhost:8080/"
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
use Behat\Mink\Session;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
private $session;
|
||||||
|
private $parameters;
|
||||||
|
|
||||||
|
public function __construct(Session $session, $minkParameters)
|
||||||
|
{
|
||||||
|
if (!is_array($minkParameters) && !$minkParameters instanceof \ArrayAccess) {
|
||||||
|
throw new \InvalidArgumentException(sprintf(
|
||||||
|
'"$parameters" passed to "%s" has to be an array or implement "%s".',
|
||||||
|
self::class,
|
||||||
|
\ArrayAccess::class
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->session = $session;
|
||||||
|
$this->parameters = $minkParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @When I visit the page :page */
|
||||||
|
public function visitPage(string $page): void
|
||||||
|
{
|
||||||
|
$this->session->visit($page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @Then I should see :content on the page */
|
||||||
|
public function shouldSeeContentOnPage(string $content): void
|
||||||
|
{
|
||||||
|
assert(false !== strpos($this->session->getPage()->getContent(), $content));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @Then the base url from Mink parameters should be :expected */
|
||||||
|
public function baseUrlShouldBe(string $expected): void
|
||||||
|
{
|
||||||
|
assert(isset($this->parameters['base_url']));
|
||||||
|
assert($this->parameters['base_url'] === $expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Injecting Mink session and Mink parameters
|
||||||
|
Given a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
App\Tests\SomeContext:
|
||||||
|
public: true
|
||||||
|
arguments:
|
||||||
|
- '@behat.mink.default_session'
|
||||||
|
- '@behat.mink.parameters'
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
|
|
||||||
|
Scenario: Autowiring and autoconfiguring Mink session and Mink parameters
|
||||||
|
Given a YAML services file containing:
|
||||||
|
"""
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
App\Tests\SomeContext: ~
|
||||||
|
"""
|
||||||
|
When I run Behat
|
||||||
|
Then it should pass
|
||||||
@@ -1,9 +1,33 @@
|
|||||||
Feature: Running bare Behat scenarios
|
Feature: Running bare Behat scenarios
|
||||||
|
|
||||||
Scenario: Running Behat with SymfonyExtension
|
Scenario: Running Behat with SymfonyExtension
|
||||||
Given a Behat configuration with the minimal working configuration for SymfonyExtension
|
Given a working Symfony application with SymfonyExtension configured
|
||||||
And a Behat configuration with the minimal working configuration for MinkExtension
|
And a Behat configuration containing:
|
||||||
And an application kernel with the minimal working configuration for SymfonyExtension
|
"""
|
||||||
And a feature file with passing scenario
|
default:
|
||||||
|
suites:
|
||||||
|
default:
|
||||||
|
contexts:
|
||||||
|
- App\Tests\SomeContext
|
||||||
|
"""
|
||||||
|
And a feature file containing:
|
||||||
|
"""
|
||||||
|
Feature:
|
||||||
|
Scenario:
|
||||||
|
Then it should pass
|
||||||
|
"""
|
||||||
|
And a context file "tests/SomeContext.php" containing:
|
||||||
|
"""
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use Behat\Behat\Context\Context;
|
||||||
|
|
||||||
|
final class SomeContext implements Context {
|
||||||
|
/** @Then it should pass */
|
||||||
|
public function itShouldPass(): void {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
When I run Behat
|
When I run Behat
|
||||||
Then it should pass
|
Then it should pass
|
||||||
|
|||||||
@@ -2,4 +2,7 @@ parameters:
|
|||||||
reportUnmatchedIgnoredErrors: false
|
reportUnmatchedIgnoredErrors: false
|
||||||
|
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
|
- '/Cannot access offset 0 on callable\./'
|
||||||
|
- '/Cannot access offset 1 on callable\./'
|
||||||
|
- '/Method FriendsOfBehat\\SymfonyExtension\\Context\\Environment\\InitialisedContextServiceEnvironment::bindCallee\(\) should return callable/'
|
||||||
- '/Cannot call method [a-zA-Z0-9]+\(\) on Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface|null\./'
|
- '/Cannot call method [a-zA-Z0-9]+\(\) on Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface|null\./'
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ final class FriendsOfBehatSymfonyExtensionExtension extends Extension implements
|
|||||||
$container
|
$container
|
||||||
->registerForAutoconfiguration(Context::class)
|
->registerForAutoconfiguration(Context::class)
|
||||||
->addTag('fob.context')
|
->addTag('fob.context')
|
||||||
|
->setBindings([
|
||||||
|
'$minkParameters' => new Reference('behat.mink.parameters'),
|
||||||
|
])
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,11 +60,12 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param UninitialisedContextServiceEnvironment $uninitializedEnvironment
|
||||||
|
*
|
||||||
* @throws EnvironmentIsolationException
|
* @throws EnvironmentIsolationException
|
||||||
*/
|
*/
|
||||||
public function isolateEnvironment(Environment $uninitializedEnvironment, $testSubject = null): Environment
|
public function isolateEnvironment(Environment $uninitializedEnvironment, $testSubject = null): Environment
|
||||||
{
|
{
|
||||||
/** @var UninitialisedContextServiceEnvironment $uninitializedEnvironment */
|
|
||||||
$this->assertEnvironmentCanBeIsolated($uninitializedEnvironment, $testSubject);
|
$this->assertEnvironmentCanBeIsolated($uninitializedEnvironment, $testSubject);
|
||||||
|
|
||||||
$environment = new InitialisedContextServiceEnvironment($uninitializedEnvironment->getSuite());
|
$environment = new InitialisedContextServiceEnvironment($uninitializedEnvironment->getSuite());
|
||||||
@@ -136,22 +137,31 @@ final class ContextServiceEnvironmentHandler implements EnvironmentHandler
|
|||||||
return $class;
|
return $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \Exception('wtf?');
|
throw new \DomainException(sprintf('There is no service or class "%s".', $contextId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getContext(string $contextId): Context
|
private function getContext(string $contextId): Context
|
||||||
{
|
{
|
||||||
if ($this->getContainer()->has($contextId)) {
|
|
||||||
return $this->getContainer()->get($contextId);
|
|
||||||
}
|
|
||||||
|
|
||||||
$class = '\\' . ltrim($contextId, '\\');
|
$class = '\\' . ltrim($contextId, '\\');
|
||||||
|
|
||||||
if (class_exists($class)) {
|
if ($this->getContainer()->has($contextId)) {
|
||||||
return new $class();
|
$context = $this->getContainer()->get($contextId);
|
||||||
|
} elseif (class_exists($class)) {
|
||||||
|
$context = new $class();
|
||||||
|
} else {
|
||||||
|
throw new \DomainException(sprintf('There is no service or class "%s".', $contextId));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \Exception('wtf?');
|
if (!$context instanceof Context) {
|
||||||
|
throw new \DomainException(sprintf(
|
||||||
|
'Context "%s" referenced as "%s" needs to implement "%s".',
|
||||||
|
get_class($context),
|
||||||
|
$contextId,
|
||||||
|
Context::class
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getContainer(): ContainerInterface
|
private function getContainer(): ContainerInterface
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ final class SymfonyDriver extends BrowserKitDriver
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($kernel->getContainer()->get('test.client'), $baseUrl);
|
$testClient = $kernel->getContainer()->get('test.client');
|
||||||
|
|
||||||
|
if (!$testClient instanceof Client) {
|
||||||
|
throw new \RuntimeException(sprintf(
|
||||||
|
'Service "test.client" should be an instance of "%s", "%s" given.',
|
||||||
|
Client::class,
|
||||||
|
get_class($testClient)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($testClient, $baseUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ final class SymfonyExtension implements Extension
|
|||||||
*/
|
*/
|
||||||
private const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel';
|
private const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel';
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $minkExtensionFound = false;
|
||||||
|
|
||||||
public function getConfigKey(): string
|
public function getConfigKey(): string
|
||||||
{
|
{
|
||||||
return 'fob_symfony';
|
return 'fob_symfony';
|
||||||
@@ -43,7 +46,14 @@ final class SymfonyExtension implements Extension
|
|||||||
|
|
||||||
public function initialize(ExtensionManager $extensionManager): void
|
public function initialize(ExtensionManager $extensionManager): void
|
||||||
{
|
{
|
||||||
$this->registerSymfonyDriverFactory($extensionManager);
|
/** @var MinkExtension|null $minkExtension */
|
||||||
|
$minkExtension = $extensionManager->getExtension('mink');
|
||||||
|
if (null === $minkExtension) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$minkExtension->registerDriverFactory(new SymfonyDriverFactory('symfony', new Reference(self::DRIVER_KERNEL_ID)));
|
||||||
|
$this->minkExtensionFound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configure(ArrayNodeDefinition $builder): void
|
public function configure(ArrayNodeDefinition $builder): void
|
||||||
@@ -75,8 +85,10 @@ final class SymfonyExtension implements Extension
|
|||||||
|
|
||||||
$this->loadEnvironmentHandler($container);
|
$this->loadEnvironmentHandler($container);
|
||||||
|
|
||||||
$this->loadMinkDefaultSession($container);
|
if ($this->minkExtensionFound) {
|
||||||
$this->loadMinkParameters($container);
|
$this->loadMinkDefaultSession($container);
|
||||||
|
$this->loadMinkParameters($container);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process(ContainerBuilder $container): void
|
public function process(ContainerBuilder $container): void
|
||||||
@@ -166,15 +178,4 @@ final class SymfonyExtension implements Extension
|
|||||||
|
|
||||||
$container->setDefinition('fob_symfony.mink.parameters', $minkParametersDefinition);
|
$container->setDefinition('fob_symfony.mink.parameters', $minkParametersDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function registerSymfonyDriverFactory(ExtensionManager $extensionManager): void
|
|
||||||
{
|
|
||||||
/** @var MinkExtension|null $minkExtension */
|
|
||||||
$minkExtension = $extensionManager->getExtension('mink');
|
|
||||||
if (null === $minkExtension) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$minkExtension->registerDriverFactory(new SymfonyDriverFactory('symfony', new Reference(self::DRIVER_KERNEL_ID)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,24 +12,16 @@ use Symfony\Component\Yaml\Yaml;
|
|||||||
|
|
||||||
final class TestContext implements Context
|
final class TestContext implements Context
|
||||||
{
|
{
|
||||||
/**
|
/** @var string */
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private static $workingDir;
|
private static $workingDir;
|
||||||
|
|
||||||
/**
|
/** @var Filesystem */
|
||||||
* @var Filesystem
|
|
||||||
*/
|
|
||||||
private static $filesystem;
|
private static $filesystem;
|
||||||
|
|
||||||
/**
|
/** @var string */
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private static $phpBin;
|
private static $phpBin;
|
||||||
|
|
||||||
/**
|
/** @var Process */
|
||||||
* @var Process
|
|
||||||
*/
|
|
||||||
private $process;
|
private $process;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,13 +51,98 @@ final class TestContext implements Context
|
|||||||
self::$filesystem->remove(self::$workingDir);
|
self::$filesystem->remove(self::$workingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Given a working Symfony application with SymfonyExtension configured
|
||||||
|
*/
|
||||||
|
public function workingSymfonyApplicationWithExtension(): void
|
||||||
|
{
|
||||||
|
$this->thereIsConfiguration(<<<'CON'
|
||||||
|
default:
|
||||||
|
extensions:
|
||||||
|
FriendsOfBehat\SymfonyExtension:
|
||||||
|
kernel:
|
||||||
|
class: App\Kernel
|
||||||
|
CON
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->thereIsFile('vendor/autoload.php', sprintf(<<<'CON'
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
$loader = require '%s';
|
||||||
|
$loader->addPsr4('App\\', __DIR__ . '/../src/');
|
||||||
|
$loader->addPsr4('App\\Tests\\', __DIR__ . '/../tests/');
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
CON
|
||||||
|
, __DIR__ . '/../../../vendor/autoload.php'));
|
||||||
|
|
||||||
|
$this->thereIsFile('src/Kernel.php', <<<'CON'
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||||
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\Kernel as HttpKernel;
|
||||||
|
use Symfony\Component\Routing\RouteCollectionBuilder;
|
||||||
|
|
||||||
|
class Kernel extends HttpKernel
|
||||||
|
{
|
||||||
|
use MicroKernelTrait;
|
||||||
|
|
||||||
|
public function helloWorld(): Response
|
||||||
|
{
|
||||||
|
return new Response('Hello world!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerBundles(): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
||||||
|
new \FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
|
||||||
|
{
|
||||||
|
$container->loadFromExtension('framework', [
|
||||||
|
'test' => $this->getEnvironment() === 'test',
|
||||||
|
'secret' => 'Pigeon',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$loader->load(__DIR__ . '/../config/services.yaml');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configureRoutes(RouteCollectionBuilder $routes)
|
||||||
|
{
|
||||||
|
$routes->add('/hello-world', 'kernel:helloWorld');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CON
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->thereIsFile('config/services.yaml', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Given /^a YAML services file containing:$/
|
||||||
|
*/
|
||||||
|
public function yamlServicesFile($content): void
|
||||||
|
{
|
||||||
|
$this->thereIsFile('config/services.yaml', (string) $content);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/
|
* @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/
|
||||||
*/
|
*/
|
||||||
public function thereIsConfiguration($content): void
|
public function thereIsConfiguration($content): void
|
||||||
{
|
{
|
||||||
$mainConfigFile = sprintf('%s/behat.yml', self::$workingDir);
|
$mainConfigFile = sprintf('%s/behat.yml', self::$workingDir);
|
||||||
$newConfigFile = sprintf('%s/behat-%s.yml', self::$workingDir, md5($content));
|
$newConfigFile = sprintf('%s/behat-%s.yml', self::$workingDir, md5((string) $content));
|
||||||
|
|
||||||
self::$filesystem->dumpFile($newConfigFile, (string) $content);
|
self::$filesystem->dumpFile($newConfigFile, (string) $content);
|
||||||
|
|
||||||
@@ -79,40 +156,6 @@ final class TestContext implements Context
|
|||||||
self::$filesystem->dumpFile($mainConfigFile, Yaml::dump($mainBehatConfiguration));
|
self::$filesystem->dumpFile($mainConfigFile, Yaml::dump($mainBehatConfiguration));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^a Behat configuration with the minimal working configuration for SymfonyExtension$/
|
|
||||||
*/
|
|
||||||
public function thereIsConfigurationWithMinimalWorkingConfigurationForSymfonyExtension(): void
|
|
||||||
{
|
|
||||||
$this->thereIsConfiguration(<<<'CON'
|
|
||||||
default:
|
|
||||||
extensions:
|
|
||||||
FriendsOfBehat\SymfonyExtension:
|
|
||||||
kernel:
|
|
||||||
path: app/AppKernel.php
|
|
||||||
class: AppKernel
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^a Behat configuration with the minimal working configuration for MinkExtension$/
|
|
||||||
*/
|
|
||||||
public function thereIsConfigurationWithMinimalWorkingConfigurationForMinkExtension(): void
|
|
||||||
{
|
|
||||||
$this->thereIsConfiguration(<<<'CON'
|
|
||||||
default:
|
|
||||||
extensions:
|
|
||||||
Behat\MinkExtension:
|
|
||||||
base_url: "http://localhost:8080/"
|
|
||||||
default_session: symfony
|
|
||||||
sessions:
|
|
||||||
symfony:
|
|
||||||
symfony: ~
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/
|
* @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/
|
||||||
*/
|
*/
|
||||||
@@ -121,42 +164,6 @@ CON
|
|||||||
self::$filesystem->dumpFile(self::$workingDir . '/' . $file, (string) $content);
|
self::$filesystem->dumpFile(self::$workingDir . '/' . $file, (string) $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^an application kernel with the minimal working configuration for SymfonyExtension$/
|
|
||||||
*/
|
|
||||||
public function thereIsKernelWithMinimalWorkingConfiguration(): void
|
|
||||||
{
|
|
||||||
$this->thereIsFile('app/AppKernel.php', <<<'CON'
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\Kernel;
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
|
||||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
|
||||||
|
|
||||||
class AppKernel extends Kernel
|
|
||||||
{
|
|
||||||
public function registerBundles()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
|
||||||
new \FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerContainerConfiguration(LoaderInterface $loader)
|
|
||||||
{
|
|
||||||
$loader->load(function (ContainerBuilder $container): void {
|
|
||||||
$container->loadFromExtension('framework', [
|
|
||||||
'test' => $this->getEnvironment() === 'test',
|
|
||||||
'secret' => 'Pigeon',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Given /^a feature file containing(?: "([^"]+)"|:)$/
|
* @Given /^a feature file containing(?: "([^"]+)"|:)$/
|
||||||
*/
|
*/
|
||||||
@@ -165,110 +172,6 @@ CON
|
|||||||
$this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content);
|
$this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^a feature file with passing scenario$/
|
|
||||||
*/
|
|
||||||
public function thereIsFeatureFileWithPassingScenario(): void
|
|
||||||
{
|
|
||||||
$this->thereIsFile('features/bootstrap/FeatureContext.php', <<<'CON'
|
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
class FeatureContext implements \Behat\Behat\Context\Context
|
|
||||||
{
|
|
||||||
/** @Then it passes */
|
|
||||||
public function itPasses() {}
|
|
||||||
}
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->thereIsFeatureFile(<<<FEA
|
|
||||||
Feature: Passing feature
|
|
||||||
|
|
||||||
Scenario: Passing scenario
|
|
||||||
Then it passes
|
|
||||||
FEA
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^a feature file with failing scenario$/
|
|
||||||
*/
|
|
||||||
public function thereIsFeatureFileWithFailingScenario(): void
|
|
||||||
{
|
|
||||||
$this->thereIsFile('features/bootstrap/FeatureContext.php', <<<'CON'
|
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
class FeatureContext implements \Behat\Behat\Context\Context
|
|
||||||
{
|
|
||||||
/** @Then it fails */
|
|
||||||
public function itFails() { throw new \RuntimeException(); }
|
|
||||||
}
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->thereIsFeatureFile(<<<FEA
|
|
||||||
Feature: Failing feature
|
|
||||||
|
|
||||||
Scenario: Failing scenario
|
|
||||||
Then it fails
|
|
||||||
FEA
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^a feature file with scenario with missing step$/
|
|
||||||
*/
|
|
||||||
public function thereIsFeatureFileWithScenarioWithMissingStep(): void
|
|
||||||
{
|
|
||||||
$this->thereIsFile('features/bootstrap/FeatureContext.php', <<<'CON'
|
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
class FeatureContext implements \Behat\Behat\Context\Context {}
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->thereIsFeatureFile(<<<FEA
|
|
||||||
Feature: Feature with missing step
|
|
||||||
|
|
||||||
Scenario: Scenario with missing step
|
|
||||||
Then it does not have this step
|
|
||||||
FEA
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Given /^a feature file with scenario with pending step$/
|
|
||||||
*/
|
|
||||||
public function thereIsFeatureFileWithScenarioWithPendingStep(): void
|
|
||||||
{
|
|
||||||
$this->thereIsFile('features/bootstrap/FeatureContext.php', <<<'CON'
|
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
class FeatureContext implements \Behat\Behat\Context\Context
|
|
||||||
{
|
|
||||||
/** @Then it has this step as pending */
|
|
||||||
public function itFails() { throw new \Behat\Behat\Tester\Exception\PendingException(); }
|
|
||||||
}
|
|
||||||
CON
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->thereIsFeatureFile(<<<FEA
|
|
||||||
Feature: Feature with pending step
|
|
||||||
|
|
||||||
Scenario: Scenario with pending step
|
|
||||||
Then it has this step as pending
|
|
||||||
FEA
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @When /^I run Behat$/
|
* @When /^I run Behat$/
|
||||||
*/
|
*/
|
||||||
@@ -290,7 +193,7 @@ FEA
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new \DomainException(
|
throw new \DomainException(
|
||||||
'Behat was expecting to pass, but failed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput()
|
'Behat was expecting to pass, but failed with the following output:' . \PHP_EOL . \PHP_EOL . $this->getProcessOutput()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +216,7 @@ FEA
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new \DomainException(
|
throw new \DomainException(
|
||||||
'Behat was expecting to fail, but passed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput()
|
'Behat was expecting to fail, but passed with the following output:' . \PHP_EOL . \PHP_EOL . $this->getProcessOutput()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,16 +252,13 @@ FEA
|
|||||||
|
|
||||||
if (0 === $result) {
|
if (0 === $result) {
|
||||||
throw new \DomainException(sprintf(
|
throw new \DomainException(sprintf(
|
||||||
'Pattern "%s" does not match the following output:' . PHP_EOL . PHP_EOL . '%s',
|
'Pattern "%s" does not match the following output:' . \PHP_EOL . \PHP_EOL . '%s',
|
||||||
$pattern,
|
$pattern,
|
||||||
$output
|
$output
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function getProcessOutput(): string
|
private function getProcessOutput(): string
|
||||||
{
|
{
|
||||||
$this->assertProcessIsAvailable();
|
$this->assertProcessIsAvailable();
|
||||||
@@ -366,9 +266,6 @@ FEA
|
|||||||
return $this->process->getErrorOutput() . $this->process->getOutput();
|
return $this->process->getErrorOutput() . $this->process->getOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
private function getProcessExitCode(): int
|
private function getProcessExitCode(): int
|
||||||
{
|
{
|
||||||
$this->assertProcessIsAvailable();
|
$this->assertProcessIsAvailable();
|
||||||
@@ -387,8 +284,6 @@ FEA
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
|
||||||
*
|
|
||||||
* @throws \RuntimeException
|
* @throws \RuntimeException
|
||||||
*/
|
*/
|
||||||
private static function findPhpBinary(): string
|
private static function findPhpBinary(): string
|
||||||
|
|||||||
Reference in New Issue
Block a user