Merge pull request #117 from stof/behat_3

Refactored the extension for Behat 3.0-RC
This commit is contained in:
Konstantin Kudryashov
2014-01-04 16:06:44 -08:00
26 changed files with 751 additions and 1028 deletions

View File

@@ -8,16 +8,18 @@ php:
env:
- SYMFONY_VERSION='2.2.*'
- SYMFONY_VERSION='2.3.*'
- SYMFONY_VERSION='2.4.*'
- SYMFONY_VERSION='2.4.*@dev'
matrix:
allow_failures:
- env: "SYMFONY_VERSION='2.4.*@dev'"
- env: "SYMFONY_VERSION='2.5.*@dev'"
before_script:
- curl http://getcomposer.org/installer | php
- php composer.phar require --no-update symfony/symfony=$SYMFONY_VERSION
- php composer.phar install --dev --prefer-source
- composer require --no-update symfony/symfony=$SYMFONY_VERSION
- composer install --prefer-source
- export PATH=./vendor/bin:$PATH
script: behat -fprogress
script:
- phpspec run -f pretty
- behat -fprogress

View File

@@ -6,7 +6,7 @@ Status](https://secure.travis-ci.org/Behat/MinkExtension.png?branch=master)](htt
Provides integration layer:
* Additional services for Behat (`Mink`, `Sessions`, `Drivers`).
* `Behat\MinkExtension\Context\MinkAwareInterface` which provides `Mink`
* `Behat\MinkExtension\Context\MinkAwareContext` which provides `Mink`
instance for your contexts or subcontexts.
* Base `Behat\MinkExtension\Context\MinkContext` context which provides base
step definitions and hooks for your contexts or subcontexts. Or it could be

View File

@@ -14,12 +14,13 @@
"require": {
"php": ">=5.3.2",
"behat/behat": "~3.0-RC1@dev",
"behat/behat": "~3.0-RC2@dev",
"behat/mink": ">=1.4.3,<1.6-dev",
"symfony/config": "~2.2"
},
"require-dev": {
"phpspec/phpspec": "2.0.*@dev",
"behat/mink-goutte-driver": "~1.0"
},

View File

@@ -9,48 +9,24 @@ and languages provide functional testing tools. Today well talk about how to
use Behat for functional testing of web applications. `Mink <http://mink.behat.org>`_
is a tool exactly for that and this extension provides integration for it.
Basically, MinkExtension is an integration layer between Behat 2.4+ and Mink 1.4+
Basically, MinkExtension is an integration layer between Behat 3.0+ and Mink 1.4+
and it provides:
* Additional services for Behat (``Mink``, ``Sessions``, ``Drivers``).
* ``Behat\MinkExtension\Context\MinkAwareInterface`` which provides ``Mink``
instance for your contexts or subcontexts.
* ``Behat\MinkExtension\Context\MinkAwareContext`` which provides ``Mink``
instance for your contexts.
* Base ``Behat\MinkExtension\Context\MinkContext`` context which provides base
step definitions and hooks for your contexts or subcontexts. Or it could be
even used as subcontext on its own.
even used as context on its own.
Installation
------------
This extension requires:
* Behat 2.4+
* Behat 3.0+
* Mink 1.4+
Through PHAR
~~~~~~~~~~~~
You should first download 3 phar archives:
* `behat.phar <http://behat.org/downloads/behat.phar>`_ - Behat itself
* `mink.phar <http://behat.org/downloads/mink.phar>`_ - Mink framework
* `mink_extension.phar <http://behat.org/downloads/mink_extension.phar>`_
- integration extension
After downloading and placing them into project directory, you need to
activate ``mink_extension.phar`` in your ``behat.yml``:
.. code-block:: yaml
# behat.yml
default:
# ...
extensions:
mink_extension.phar:
mink_loader: 'mink-VERSION.phar'
base_url: 'http://example.com'
goutte: ~
Through Composer
~~~~~~~~~~~~~~~~
@@ -61,10 +37,10 @@ The easiest way to keep your suite updated is to use `Composer <http://getcompos
.. code-block:: js
{
"require": {
"require-dev": {
...
"behat/mink-extension": "*"
"behat/mink-extension": "~2.0@dev"
}
}
@@ -72,8 +48,7 @@ The easiest way to keep your suite updated is to use `Composer <http://getcompos
.. code-block:: bash
$ curl http://getcomposer.org/installer | php
$ php composer.phar install
$ composer update behat/mink-extension
3. Activate extension by specifying its class in your ``behat.yml``:
@@ -92,23 +67,15 @@ Usage
After installing extension, there would be 6 usage options available for you:
1. Writing features with bundled steps only. In this case, you don't need to create
``bootstrap/`` folder or custom ``FeatureContext`` class - Behat will use default
``MinkContext`` by default. To see all available steps, run:
.. code-block:: bash
$ bin/behat -di
2. Subcontexting/extending ``Behat\MinkExtension\Context\RawMinkContext`` in your feature suite.
1. Extending ``Behat\MinkExtension\Context\RawMinkContext`` in your feature suite.
This will give you ability to use preconfigured `Mink` instance altogether with some
convenience methods:
* ``getSession($name = null)``
* ``assertSession($name = null)``
``RawMinkContext`` doesn't provide any hooks or definitions, so you can inherit from it
in as many subcontexts as you want - you'll never get ``RedundantStepException``.
in as many contexts as you want - you'll never get ``RedundantStepException``.
3. Extending ``Behat\MinkExtension\Context\MinkContext`` with one of your contexts.
2. Extending ``Behat\MinkExtension\Context\MinkContext`` with one of your contexts.
Exactly like previous option, but also provides lot of predefined step definitions out
of the box. As this context provides step definitions and hooks, you can use it **only once**
inside your feature context tree.
@@ -136,24 +103,18 @@ After installing extension, there would be 6 usage options available for you:
It will cause ``RedundantException``. So, you can inherit from ``MinkContext``
only with one of your context/subcontext classes.
4. Subcontexting ``Behat\MinkExtension\Context\MinkContext`` in your main context.
3. Adding ``Behat\MinkExtension\Context\MinkContext`` as context in your suite.
Exactly like previous option, but gives you ability to keep your main context
class clean.
.. code-block:: php
.. code-block:: yaml
<?php
use Behat\MinkExtension\Context\RawMinkContext;
use Behat\MinkExtension\Context\MinkContext;
class FeatureContext extends RawMinkContext
{
public function __construct(array $parameters)
{
$this->useContext('mink', new MinkContext);
}
}
default:
suites:
my_suite:
contexts:
- FeatureContext
- Behat\MinkExtension\Context\MinkContext
.. note::
@@ -161,17 +122,10 @@ After installing extension, there would be 6 usage options available for you:
It will cause ``RedundantException``. So, you can inherit from ``MinkContext``
only with one of your context/subcontext classes.
.. note::
Here, we are also extending our main context from ``RawMinkContext`` class.
This class doesn't provide any definitions or hooks - just helper methods
for you to interact with Mink. It means, that you could extend ``RawMinkContext``
with as many context classes in your suite as you want.
5. If you're on the php 5.4+, you can simply use ``Behat\MinkExtension\Context\MinkDictionary``
trait inside your ``FeatureContext`` or any of its subcontexts. This trait will provide
all the needed methods, hooks and definitions for you to start. You can use this trait **only
once** inside your feature context tree.
4. If you're on the php 5.4+, you can simply use ``Behat\MinkExtension\Context\MinkDictionary``
trait inside your ``FeatureContext``. This trait will provide all the needed methods,
hooks and definitions for you to start. You can use this trait **only once** inside
your feature context tree, and it cannot be used at the same time than the ``MinkContext``.
.. code-block:: php
@@ -193,10 +147,9 @@ After installing extension, there would be 6 usage options available for you:
}
}
6. Implementing ``Behat\MinkExtension\Context\MinkAwareInterface`` with your context or its
subcontexts.
5. Implementing ``Behat\MinkExtension\Context\MinkAwareContext`` with your context.
There's common things between last 5 methods. In each of those, target context will implement
There's common things these methods. In each of those, target context will implement
``setMink(Mink $mink)`` and ``setMinkParameters(array $parameters)`` methods. Those methods would
be automatically called **immediately after** each context creation before each scenario. And
this ``$mink`` instance will be preconfigured based on the settings you've provided in your
@@ -212,7 +165,7 @@ Drivers
~~~~~~~
First of all, there's drivers enabling configuration. MinkExtension comes
with support for 5 drivers out of the box:
with support for 6 drivers out of the box:
* ``GoutteDriver`` - default headless driver. It is used by default, which means
that if you didn't changed ``default_session`` (another parameter) - you should
@@ -226,12 +179,12 @@ with support for 5 drivers out of the box:
goutte: ~
.. Tips : HTTPS and self-signed certificate
In case you use Behat/Mink/Goutte to test your application, and want to test an
application secured with HTTPS, but with a self-signed certificate, you can use
In case you use Behat/Mink/Goutte to test your application, and want to test an
application secured with HTTPS, but with a self-signed certificate, you can use
the following parameters to avoid the validation error triggered by Guzzle :
.. code-block:: yaml
default:
extensions:
Behat\MinkExtension\Extension:
@@ -252,6 +205,20 @@ the following parameters to avoid the validation error triggered by Guzzle :
Behat\MinkExtension\Extension:
selenium2: ~
* ``SaucelabsDriver`` - special flavor of the Selenium2Driver configured to use the
selenium2 hosted installation of saucelabs.com. You could use it by setting it in
``javascript_session`` to ``saucelabs`` and by marking scenarios as ``@javascript``
or simply by marking scenarios with ``mink:saucelabs`` (no need to switch
``javascript_session`` in this case). In order to enable it, modify your ``behat.yml``
profile:
.. code-block:: yaml
default:
extensions:
Behat\MinkExtension\Extension:
saucelabs: ~
* ``SeleniumDriver`` - another javascript driver. You could use it by setting it
in ``javascript_session`` to ``selenium`` and by marking scenarios as ``@javascript``
or simply by marking scenarios with ``mink:selenium`` (no need to switch
@@ -300,7 +267,7 @@ the following parameters to avoid the validation error triggered by Guzzle :
- GoutteDriver - ``behat/mink-goutte-driver``
- SeleniumDriver - ``behat/mink-selenium-driver``
- WebDriver - ``behat/mink-selenium2-driver``
- Selenium2Driver (also used for Saucelabs) - ``behat/mink-selenium2-driver``
- SahiDriver - ``behat/mink-sahi-driver``
- ZombieDriver - ``behat/mink-zombie-driver``
@@ -326,10 +293,16 @@ There's other useful parameters, that you can use to configure your suite:
currently opened page into temporary file and opens it with some browser
utility (for debugging). This option defines command to be used for opening.
For example: ``show_cmd: 'firefox %s'``.
* ``browser_name`` - metaoption, that defines which browser to use for Sahi,
* ``show_tmp_dir`` - the temporary folder used to show the opened page (defaults
to the system temp dir)
* ``show_auto`` - Whether the opened page should be shown automatically when
a step fails.
* ``browser_name`` - meta-option, that defines which browser to use for Sahi,
Selenium and Selenium2 drivers.
* ``default_session`` - defines default session (driver) to be used for all
untagged scenarios. Could be any enabled driver name.
untagged scenarios. Could be any enabled driver name. Defaults to ``goutte``
* ``javascript_session`` - defines javascript session (driver) (the one, which
will be used for ``@javascript`` tagged scenarios). Could be any enabled driver
name.
name. Defaults to ``selenium2``
* ``mink_loader`` - path to a file loaded to make Mink available (useful when
using the PHAR archive for Mink, useless when using Composer)

View File

@@ -0,0 +1,33 @@
<?php
namespace spec\Behat\MinkExtension\Context\Initializer;
use Behat\Behat\Context\Context;
use Behat\Mink\Mink;
use Behat\MinkExtension\Context\MinkAwareContext;
use PhpSpec\ObjectBehavior;
class MinkAwareInitializerSpec extends ObjectBehavior
{
function let(Mink $mink)
{
$this->beConstructedWith($mink, array('base_url' => 'foo'));
}
function it_is_a_context_initializer()
{
$this->shouldHaveType('Behat\Behat\Context\Initializer\ContextInitializer');
}
function it_does_nothing_for_basic_contexts(Context $context)
{
$this->initializeContext($context);
}
function it_injects_mink_and_parameters_in_mink_aware_contexts(MinkAwareContext $context, $mink)
{
$context->setMink($mink)->shouldBeCalled();
$context->setMinkParameters(array('base_url' => 'foo'))->shouldBeCalled();
$this->initializeContext($context);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace spec\Behat\MinkExtension;
use PhpSpec\ObjectBehavior;
class ExtensionSpec extends ObjectBehavior
{
function it_is_a_testwork_extension()
{
$this->shouldHaveType('Behat\Testwork\ServiceContainer\Extension');
}
function it_is_named_mink()
{
$this->getConfigKey()->shouldReturn('mink');
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace spec\Behat\MinkExtension\Listener;
use Behat\Behat\Tester\Event\ScenarioTested;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Mink\Mink;
use PhpSpec\ObjectBehavior;
class SessionsListenerSpec extends ObjectBehavior
{
function let(Mink $mink, ScenarioTested $event, FeatureNode $feature, ScenarioNode $scenario)
{
$this->beConstructedWith($mink, array('default_session' => 'goutte', 'javascript_session' => 'selenium2'));
$event->getFeature()->willReturn($feature);
$event->getScenario()->willReturn($scenario);
$feature->hasTag('insulated')->willReturn(false);
$feature->getTags()->willReturn(array());
$scenario->hasTag('insulated')->willReturn(false);
$scenario->getTags()->willReturn(array());
}
function it_is_an_event_subscriber()
{
$this->shouldHaveType('Symfony\Component\EventDispatcher\EventSubscriberInterface');
}
function it_resets_the_default_session_before_scenarios($event, $mink)
{
$mink->resetSessions()->shouldBeCalled();
$mink->setDefaultSessionName('goutte')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_switches_to_the_javascript_session_for_tagged_scenarios($event, $mink, $scenario)
{
$scenario->getTags()->willReturn(array('javascript'));
$mink->resetSessions()->shouldBeCalled();
$mink->setDefaultSessionName('selenium2')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_switches_to_the_javascript_session_for_tagged_features($event, $mink, $feature)
{
$feature->getTags()->willReturn(array('javascript'));
$mink->resetSessions()->shouldBeCalled();
$mink->setDefaultSessionName('selenium2')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_switches_to_a_named_session($event, $mink, $scenario)
{
$scenario->getTags()->willReturn(array('mink:test'));
$mink->resetSessions()->shouldBeCalled();
$mink->setDefaultSessionName('test')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_prefers_the_scenario_over_the_feature($event, $mink, $scenario, $feature)
{
$scenario->getTags()->willReturn(array('mink:test'));
$feature->getTags()->willReturn(array('javascript'));
$mink->resetSessions()->shouldBeCalled();
$mink->setDefaultSessionName('test')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_stops_the_sessions_for_insulated_scenarios($event, $mink, $scenario)
{
$scenario->hasTag('insulated')->willReturn(true);
$mink->stopSessions()->shouldBeCalled();
$mink->setDefaultSessionName('goutte')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_stops_the_sessions_for_insulated_features($event, $mink, $feature)
{
$feature->hasTag('insulated')->willReturn(true);
$mink->stopSessions()->shouldBeCalled();
$mink->setDefaultSessionName('goutte')->shouldBeCalled();
$this->prepareDefaultMinkSession($event);
}
function it_stops_the_sessions_at_the_end_of_the_exercise($mink)
{
$mink->stopSessions()->shouldBeCalled();
$this->tearDownMinkSessions();
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace Behat\MinkExtension\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat\MinkExtension
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Selectors handler compilation pass. Registers all available Mink selector engines.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class SelectorsPass implements CompilerPassInterface
{
/**
* Registers additional Mink selector handlers.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.mink.selector.handler')) {
return;
}
$handlerDefinition = $container->getDefinition('behat.mink.selector.handler');
foreach ($container->findTaggedServiceIds('behat.mink.selector') as $id => $attributes) {
foreach ($attributes as $attribute) {
if (isset($attribute['alias']) && $alias = $attribute['alias']) {
$handlerDefinition->addMethodCall(
'registerSelector', array($alias, new Reference($id))
);
}
}
}
}
}

View File

@@ -1,52 +0,0 @@
<?php
namespace Behat\MinkExtension\Compiler;
use Symfony\Component\DependencyInjection\Reference,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/*
* This file is part of the Behat\MinkExtension
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Behat\Mink container compilation pass.
* Registers all available in controller Mink sessions.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class SessionsPass implements CompilerPassInterface
{
/**
* Registers Mink sessions.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('behat.mink')) {
return;
}
$minkDefinition = $container->getDefinition('behat.mink');
foreach ($container->findTaggedServiceIds('behat.mink.session') as $id => $attributes) {
foreach ($attributes as $attribute) {
if (isset($attribute['alias']) && $name = $attribute['alias']) {
$minkDefinition->addMethodCall(
'registerSession', array($name, new Reference($id))
);
}
}
}
$minkDefinition->addMethodCall(
'setDefaultSessionName', array($container->getParameter('behat.mink.default_session'))
);
}
}

View File

@@ -1,22 +0,0 @@
<?php
namespace Behat\MinkExtension\Context\ClassGuesser;
use Behat\Behat\Context\ClassGuesser\ClassGuesserInterface;
/**
* Mink context class guesser.
* Provides Mink context class if no other class found.
*/
class MinkContextClassGuesser implements ClassGuesserInterface
{
/**
* Tries to guess context classname.
*
* @return string
*/
public function guess()
{
return 'Behat\\MinkExtension\\Context\\MinkContext';
}
}

View File

@@ -1,20 +1,20 @@
<?php
/*
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Context\Initializer;
use Behat\Behat\Context\Context;
use Behat\Behat\Context\Initializer\ContextInitializer;
use Behat\Mink\Mink;
use Behat\MinkExtension\Context\MinkAwareInterface;
/*
* This file is part of the Behat\MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Behat\MinkExtension\Context\MinkAwareContext;
/**
* Mink aware contexts initializer.
@@ -40,20 +40,29 @@ class MinkAwareInitializer implements ContextInitializer
}
/**
* Checks if initializer supports provided context.
* Initializes provided context.
*
* @param Context $context
*/
public function initializeContext(Context $context)
{
if (!$context instanceof MinkAwareContext && !$this->usesMinkDictionary($context)) {
return;
}
$context->setMink($this->mink);
$context->setMinkParameters($this->parameters);
}
/**
* Checks whether the context uses the MinkDictionary trait.
*
* @param Context $context
*
* @return Boolean
*/
public function supportsContext(Context $context)
private function usesMinkDictionary(Context $context)
{
// if context/subcontext implements MinkAwareInterface
if ($context instanceof MinkAwareInterface) {
return true;
}
// if context/subcontext uses MinkDictionary trait
$refl = new \ReflectionObject($context);
if (method_exists($refl, 'getTraitNames')) {
if (in_array('Behat\\MinkExtension\\Context\\MinkDictionary', $refl->getTraitNames())) {
@@ -63,15 +72,4 @@ class MinkAwareInitializer implements ContextInitializer
return false;
}
/**
* Initializes provided context.
*
* @param Context $context
*/
public function initializeContext(Context $context)
{
$context->setMink($this->mink);
$context->setMinkParameters($this->parameters);
}
}

View File

@@ -1,23 +1,24 @@
<?php
namespace Behat\MinkExtension\Context;
use Behat\Mink\Mink;
/*
* This file is part of the Behat\MinkExtension.
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Context;
use Behat\Behat\Context\Context;
use Behat\Mink\Mink;
/**
* Mink aware interface for contexts.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface MinkAwareInterface
interface MinkAwareContext extends Context
{
/**
* Sets Mink instance.

View File

@@ -1,18 +1,18 @@
<?php
namespace Behat\MinkExtension\Context;
use Behat\Behat\Context\TranslatableContext;
use Behat\Gherkin\Node\TableNode;
/*
* This file is part of the Behat\MinkExtension.
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Context;
use Behat\Behat\Context\TranslatableContext;
use Behat\Gherkin\Node\TableNode;
/**
* Mink context for Behat BDD tool.
* Provides Mink integration and base step definitions.

View File

@@ -1,21 +1,20 @@
<?php
namespace Behat\MinkExtension\Context;
use Behat\Gherkin\Node\TableNode;
use Behat\Mink\Mink,
Behat\Mink\Session,
Behat\Mink\WebAssert;
/*
* This file is part of the Behat\MinkExtension.
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Context;
use Behat\Gherkin\Node\TableNode;
use Behat\Mink\Mink;
use Behat\Mink\Session;
use Behat\Mink\WebAssert;
/**
* Mink steps dictionary for Behat BDD tool.
*

View File

@@ -1,28 +1,26 @@
<?php
namespace Behat\MinkExtension\Context;
use Behat\Behat\Context\Context;
use Behat\Mink\Mink,
Behat\Mink\WebAssert,
Behat\Mink\Session;
/*
* This file is part of the Behat\MinkExtension.
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Context;
use Behat\Mink\Mink;
use Behat\Mink\WebAssert;
use Behat\Mink\Session;
/**
* Raw Mink context for Behat BDD tool.
* Provides raw Mink integration (without step definitions) and web assertions.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class RawMinkContext implements MinkAwareInterface, Context
class RawMinkContext implements MinkAwareContext
{
private $mink;
private $minkParameters;
@@ -133,10 +131,10 @@ class RawMinkContext implements MinkAwareInterface, Context
/**
* Save a screenshot of the current window to the file system.
*
* @param string $filename Desired filename, defaults to
* <browser_name>_<ISO 8601 date>_<randomId>.png
* @param string $filepath Desired filepath, defaults to
* upload_tmp_dir, falls back to sys_get_temp_dir()
* @param string $filename Desired filename, defaults to
* <browser_name>_<ISO 8601 date>_<randomId>.png
* @param string $filepath Desired filepath, defaults to
* upload_tmp_dir, falls back to sys_get_temp_dir()
*/
public function saveScreenshot($filename = null, $filepath = null)
{

View File

@@ -1,24 +1,23 @@
<?php
/*
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension;
use Behat\MinkExtension\Compiler\SelectorsPass;
use Behat\MinkExtension\Compiler\SessionsPass;
use Symfony\Component\Config\FileLocator,
Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Behat\Behat\Context\ServiceContainer\ContextExtension;
use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension;
use Behat\Testwork\ServiceContainer\Exception\ProcessingException;
use Behat\Testwork\ServiceContainer\Extension as BaseExtension;
/*
* This file is part of the Behat\MinkExtension
*
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Mink extension for Behat class.
@@ -27,16 +26,19 @@ use Behat\Testwork\ServiceContainer\Extension as BaseExtension;
*/
class Extension implements BaseExtension
{
const MINK_ID = 'mink';
const SELECTORS_HANDLER_ID = 'mink.selectors_handler';
const SESSION_TAG = 'mink.session';
const SELECTOR_TAG = 'mink.selector';
/**
* {@inheritDoc}
*/
public function load(ContainerBuilder $container, array $config)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/services'));
$loader->load('core.xml');
if (isset($config['mink_loader'])) {
$basePath = $container->getParameter('behat.paths.base');
$basePath = $container->getParameter('paths.base');
if (file_exists($basePath.DIRECTORY_SEPARATOR.$config['mink_loader'])) {
require($basePath.DIRECTORY_SEPARATOR.$config['mink_loader']);
@@ -45,116 +47,45 @@ class Extension implements BaseExtension
}
}
if (isset($config['goutte'])) {
if (!class_exists('Behat\\Mink\\Driver\\GoutteDriver')) {
throw new \RuntimeException(
'Install MinkGoutteDriver in order to activate goutte session.'
);
}
$loader->load('sessions/goutte.xml');
}
if (isset($config['sahi'])) {
if (!class_exists('Behat\\Mink\\Driver\\SahiDriver')) {
throw new \RuntimeException(
'Install MinkSahiDriver in order to activate sahi session.'
);
}
$loader->load('sessions/sahi.xml');
}
if (isset($config['zombie'])) {
if (!class_exists('Behat\\Mink\\Driver\\ZombieDriver')) {
throw new \RuntimeException(
'Install MinkZombieDriver in order to activate zombie session.'
);
}
$loader->load('sessions/zombie.xml');
}
if (isset($config['selenium'])) {
if (!class_exists('Behat\\Mink\\Driver\\SeleniumDriver')) {
throw new \RuntimeException(
'Install MinkSeleniumDriver in order to activate selenium session.'
);
}
$loader->load('sessions/selenium.xml');
}
if (isset($config['selenium2'])) {
if (!class_exists('Behat\\Mink\\Driver\\Selenium2Driver')) {
throw new \RuntimeException(
'Install MinkSelenium2Driver in order to activate selenium2 session.'
);
}
$loader->load('sessions/selenium2.xml');
}
if (isset($config['saucelabs'])) {
if (!class_exists('Behat\\Mink\\Driver\\Selenium2Driver')) {
throw new \RuntimeException(
'Install MinkSelenium2Driver in order to activate saucelabs session.'
);
}
$loader->load('sessions/saucelabs.xml');
}
$minkParameters = array();
foreach ($config as $ns => $tlValue) {
if (!is_array($tlValue)) {
$minkParameters[$ns] = $tlValue;
} else {
foreach ($tlValue as $name => $value) {
if ('guzzle_parameters' === $name) {
$value['redirect.disable'] = true;
}
$container->setParameter("behat.mink.$ns.$name", $value);
}
}
}
$container->setParameter('behat.mink.parameters', $minkParameters);
if (isset($config['saucelabs'])) {
$capabilities = $container->getParameter('behat.mink.saucelabs.capabilities');
$capabilities['tags'] = array(php_uname('n'), 'PHP '.phpversion());
if (getenv('TRAVIS_JOB_NUMBER')) {
$capabilities['tunnel-identifier'] = getenv('TRAVIS_JOB_NUMBER');
$capabilities['build'] = getenv('TRAVIS_BUILD_NUMBER');
$capabilities['tags'] = array('Travis-CI', 'PHP '.phpversion());
}
$container->setParameter('behat.mink.saucelabs.capabilities', $capabilities);
$host = 'ondemand.saucelabs.com';
if ($config['saucelabs']['connect']) {
$host = 'localhost:4445';
}
$username = $config['saucelabs']['username'];
$accessKey = $config['saucelabs']['access_key'];
$container->setParameter('behat.mink.saucelabs.wd_host', sprintf(
'%s:%s@%s/wd/hub', $username, $accessKey, $host
));
}
if (isset($config['base_url'])) {
$container->setParameter('behat.mink.base_url', $config['base_url']);
}
$container->setParameter('behat.mink.default_session', $config['default_session']);
$container->setParameter('behat.mink.javascript_session', $config['javascript_session']);
$container->setParameter('behat.mink.browser_name', $config['browser_name']);
$minkReflection = new \ReflectionClass('Behat\Mink\Mink');
$minkLibPath = realpath(dirname($minkReflection->getFilename()) . '/../../../');
$container->setParameter('mink.paths.lib', $minkLibPath);
$this->loadMink($container);
$this->loadContextInitializer($container);
$this->loadSelectorsHandler($container);
$this->loadSessionsListener($container);
if ($config['show_auto']) {
$loader->load('failure_show_listener.xml');
$this->loadFailureShowListener($container);
}
if (isset($config['goutte'])) {
$this->loadGoutteSession($container, $config['goutte']);
unset($config['goutte']);
}
if (isset($config['sahi'])) {
$this->loadSahiSession($container, $config['sahi']);
unset($config['sahi']);
}
if (isset($config['zombie'])) {
$this->loadZombieSession($container, $config['zombie']);
unset($config['zombie']);
}
if (isset($config['selenium'])) {
$this->loadSeleniumSession($container, $config['selenium']);
unset($config['zombie']);
}
if (isset($config['selenium2'])) {
$this->loadSelenium2Session($container, $config['selenium2']);
unset($config['selenium2']);
}
if (isset($config['saucelabs'])) {
$this->loadSaucelabsSession($container, $config['saucelabs']);
unset($config['saucelabs']);
}
$container->setParameter('mink.parameters', $config);
$container->setParameter('mink.base_url', $config['base_url']);
$container->setParameter('mink.default_session', $config['default_session']);
$container->setParameter('mink.javascript_session', $config['javascript_session']);
$container->setParameter('mink.browser_name', $config['browser_name']);
}
/**
@@ -162,244 +93,160 @@ class Extension implements BaseExtension
*/
public function configure(ArrayNodeDefinition $builder)
{
$config = $this->loadEnvironmentConfiguration();
$builder
->addDefaultsIfNotSet()
->children()
->scalarNode('mink_loader')->defaultNull()->end()
->scalarNode('base_url')->defaultNull()->end()
->scalarNode('files_path')->defaultNull()->end()
->booleanNode('show_auto')->defaultFalse()->end()
->scalarNode('show_cmd')->defaultNull()->end()
->scalarNode('show_tmp_dir')->defaultValue(sys_get_temp_dir())->end()
->scalarNode('default_session')->defaultValue('goutte')->end()
->scalarNode('javascript_session')->defaultValue('selenium2')->end()
->scalarNode('browser_name')->defaultValue('firefox')->end()
->arrayNode('goutte')
->children()
->arrayNode('server_parameters')
->useAttributeAsKey('key')
->prototype('variable')->end()
->end()
->arrayNode('guzzle_parameters')
->useAttributeAsKey('key')
->prototype('variable')->end()
->validate()
->always()
->then(function ($v) {
$v['redirect.disable'] = true;
$builder->
children()->
scalarNode('mink_loader')->
defaultValue(isset($config['mink_loader']) ? $config['mink_loader'] : null)->
end()->
scalarNode('base_url')->
defaultValue(isset($config['base_url']) ? $config['base_url'] : null)->
end()->
scalarNode('files_path')->
defaultValue(isset($config['files_path']) ? $config['files_path'] : null)->
end()->
booleanNode('show_auto')->
defaultValue(isset($config['show_auto']) ? 'true' === $config['show_auto'] : false)->
end()->
scalarNode('show_cmd')->
defaultValue(isset($config['show_cmd']) ? $config['show_cmd'] : null)->
end()->
scalarNode('show_tmp_dir')->
defaultValue(isset($config['show_tmp_dir']) ? $config['show_tmp_dir'] : sys_get_temp_dir())->
end()->
scalarNode('default_session')->
defaultValue(isset($config['default_session']) ? $config['default_session'] : 'goutte')->
end()->
scalarNode('javascript_session')->
defaultValue(isset($config['javascript_session']) ? $config['javascript_session'] : 'selenium2')->
end()->
scalarNode('browser_name')->
defaultValue(isset($config['browser_name']) ? $config['browser_name'] : 'firefox')->
end()->
arrayNode('goutte')->
children()->
arrayNode('server_parameters')->
useAttributeAsKey('key')->
prototype('variable')->end()->
end()->
arrayNode('guzzle_parameters')->
useAttributeAsKey('key')->
prototype('variable')->end()->
end()->
end()->
end()->
arrayNode('sahi')->
children()->
scalarNode('sid')->
defaultValue(isset($config['sahi']['sid']) ? $config['sahi']['sid'] : null)->
end()->
scalarNode('host')->
defaultValue('localhost')->
end()->
scalarNode('port')->
defaultValue(isset($config['sahi']['port']) ? $config['sahi']['port'] : 9999)->
end()->
scalarNode('browser')->
defaultValue(isset($config['sahi']['browser']) ? $config['sahi']['browser'] : null)->
end()->
scalarNode('limit')->
defaultValue(isset($config['sahi']['limit']) ? $config['sahi']['limit'] : 600)->
end()->
end()->
end()->
arrayNode('zombie')->
children()->
scalarNode('host')->
defaultValue(isset($config['zombie']['host']) ? $config['zombie']['host'] : '127.0.0.1')->
end()->
scalarNode('port')->
defaultValue(isset($config['zombie']['port']) ? $config['zombie']['port'] : 8124)->
end()->
scalarNode('auto_server')->
defaultValue(isset($config['zombie']['auto_server']) ? $config['zombie']['auto_server'] : true)->
end()->
scalarNode('node_bin')->
defaultValue(isset($config['zombie']['node_bin']) ? $config['zombie']['node_bin'] : 'node')->
end()->
scalarNode('server_path')->
defaultValue(isset($config['zombie']['server_path']) ? $config['zombie']['server_path'] : null)->
end()->
scalarNode('threshold')->
defaultValue(isset($config['zombie']['threshold']) ? $config['zombie']['threshold'] : 2000000)->
end()->
scalarNode('node_modules_path')->
defaultValue(isset($config['zombie']['node_modules_path']) ? $config['zombie']['node_modules_path'] : '')->
end()->
end()->
end()->
arrayNode('selenium')->
children()->
scalarNode('host')->
defaultValue(isset($config['selenium']['host']) ? $config['selenium']['host'] : '127.0.0.1')->
end()->
scalarNode('port')->
defaultValue(isset($config['selenium']['port']) ? $config['selenium']['port'] : 4444)->
end()->
scalarNode('browser')->
defaultValue(isset($config['selenium']['browser']) ? $config['selenium']['browser'] : '*%behat.mink.browser_name%')->
end()->
end()->
end()->
arrayNode('selenium2')->
children()->
scalarNode('browser')->
defaultValue(isset($config['selenium2']['browser']) ? $config['selenium2']['browser'] : '%behat.mink.browser_name%')->
end()->
arrayNode('capabilities')->
normalizeKeys(false)->
children()->
scalarNode('browserName')->
defaultValue(isset($config['selenium2']['capabilities']['browserName']) ? $config['selenium2']['capabilities']['browserName'] : 'firefox')->
end()->
scalarNode('version')->
defaultValue(isset($config['selenium2']['capabilities']['version']) ? $config['selenium2']['capabilities']['version'] : "9")->
end()->
scalarNode('platform')->
defaultValue(isset($config['selenium2']['capabilities']['platform']) ? $config['selenium2']['capabilities']['platform'] : 'ANY')->
end()->
scalarNode('browserVersion')->
defaultValue(isset($config['selenium2']['capabilities']['browserVersion']) ? $config['selenium2']['capabilities']['browserVersion'] : "9")->
end()->
scalarNode('browser')->
defaultValue(isset($config['selenium2']['capabilities']['browser']) ? $config['selenium2']['capabilities']['browser'] : 'firefox')->
end()->
scalarNode('ignoreZoomSetting')->
defaultValue(isset($config['selenium2']['capabilities']['ignoreZoomSetting']) ? $config['selenium2']['capabilities']['ignoreZoomSetting'] : 'false')->
end()->
scalarNode('name')->
defaultValue(isset($config['selenium2']['capabilities']['name']) ? $config['selenium2']['capabilities']['name'] : 'Behat Test')->
end()->
scalarNode('deviceOrientation')->
defaultValue(isset($config['selenium2']['capabilities']['deviceOrientation']) ? $config['selenium2']['capabilities']['deviceOrientation'] : 'portrait')->
end()->
scalarNode('deviceType')->
defaultValue(isset($config['selenium2']['capabilities']['deviceType']) ? $config['selenium2']['capabilities']['deviceType'] : 'tablet')->
end()->
scalarNode('selenium-version')->
defaultValue(isset($config['selenium2']['capabilities']['selenium-version']) ? $config['selenium2']['capabilities']['selenium-version'] : '2.31.0')->
end()->
scalarNode('max-duration')->
defaultValue(isset($config['selenium2']['capabilities']['max-duration']) ? $config['selenium2']['capabilities']['max-duration'] : '300')->
end()->
booleanNode('javascriptEnabled')->end()->
booleanNode('databaseEnabled')->end()->
booleanNode('locationContextEnabled')->end()->
booleanNode('applicationCacheEnabled')->end()->
booleanNode('browserConnectionEnabled')->end()->
booleanNode('webStorageEnabled')->end()->
booleanNode('rotatable')->end()->
booleanNode('acceptSslCerts')->end()->
booleanNode('nativeEvents')->end()->
booleanNode('passed')->end()->
booleanNode('record-video')->end()->
booleanNode('record-screenshots')->end()->
booleanNode('capture-html')->end()->
booleanNode('disable-popup-handler')->end()->
arrayNode('proxy')->
children()->
scalarNode('proxyType')->end()->
scalarNode('proxyAuthconfigUrl')->end()->
scalarNode('ftpProxy')->end()->
scalarNode('httpProxy')->end()->
scalarNode('sslProxy')->end()->
end()->
validate()->
ifTrue(function ($v) {
return $v;
})
->end()
->end()
->end()
->end()
->arrayNode('sahi')
->children()
->scalarNode('sid')->defaultNull()->end()
->scalarNode('host')->defaultValue('localhost')->end()
->scalarNode('port')->defaultValue(9999)->end()
->scalarNode('browser')->defaultNull()->end()
->scalarNode('limit')->defaultValue(600)->end()
->end()
->end()
->arrayNode('zombie')
->children()
->scalarNode('host')->defaultValue('127.0.0.1')->end()
->scalarNode('port')->defaultValue(8124)->end()
->booleanNode('auto_server')->defaultValue(true)->end()
->scalarNode('node_bin')->defaultValue('node')->end()
->scalarNode('server_path')->defaultNull()->end()
->scalarNode('threshold')->defaultValue(2000000)->end()
->scalarNode('node_modules_path')->defaultValue('')->end()
->end()
->end()
->arrayNode('selenium')
->children()
->scalarNode('host')->defaultValue('127.0.0.1')->end()
->scalarNode('port')->defaultValue(4444)->end()
->scalarNode('browser')->defaultValue('*%mink.browser_name%')->end()
->end()
->end()
->arrayNode('selenium2')
->children()
->scalarNode('browser')->defaultValue('%mink.browser_name%')->end()
->arrayNode('capabilities')
->addDefaultsIfNotSet()
->normalizeKeys(false)
->children()
->scalarNode('browserName')->defaultValue('firefox')->end()
->scalarNode('version')->defaultValue('9')->end()
->scalarNode('platform')->defaultValue('ANY')->end()
->scalarNode('browserVersion')->defaultValue('9')->end()
->scalarNode('browser')->defaultValue('firefox')->end()
->scalarNode('ignoreZoomSetting')->defaultValue('false')->end()
->scalarNode('name')->defaultValue('Behat Test')->end()
->scalarNode('deviceOrientation')->defaultValue('portrait')->end()
->scalarNode('deviceType')->defaultValue('tablet')->end()
->scalarNode('selenium-version')->defaultValue('2.31.0')->end()
->scalarNode('max-duration')->defaultValue('300')->end()
->booleanNode('javascriptEnabled')->end()
->booleanNode('databaseEnabled')->end()
->booleanNode('locationContextEnabled')->end()
->booleanNode('applicationCacheEnabled')->end()
->booleanNode('browserConnectionEnabled')->end()
->booleanNode('webStorageEnabled')->end()
->booleanNode('rotatable')->end()
->booleanNode('acceptSslCerts')->end()
->booleanNode('nativeEvents')->end()
->booleanNode('passed')->end()
->booleanNode('record-video')->end()
->booleanNode('record-screenshots')->end()
->booleanNode('capture-html')->end()
->booleanNode('disable-popup-handler')->end()
->arrayNode('proxy')
->children()
->scalarNode('proxyType')->end()
->scalarNode('proxyAuthconfigUrl')->end()
->scalarNode('ftpProxy')->end()
->scalarNode('httpProxy')->end()
->scalarNode('sslProxy')->end()
->end()
->validate()
->ifTrue(function ($v) {
return empty($v);
})->
thenUnset()->
end()->
end()->
arrayNode('firefox')->
children()->
scalarNode('profile')->
validate()->
ifTrue(function ($v) {
return !file_exists($v);
})->
thenInvalid('Cannot find profile zip file %s')->
end()->
end()->
scalarNode('binary')->end()->
end()->
end()->
arrayNode('chrome')->
children()->
arrayNode('switches')->
prototype('scalar')->end()->
end()->
scalarNode('binary')->end()->
arrayNode('extensions')->
prototype('scalar')->end()->
end()->
end()->
end()->
end()->
end()->
scalarNode('wd_host')->
defaultValue(isset($config['selenium2']['wd_host']) ? $config['selenium2']['wd_host'] : 'http://localhost:4444/wd/hub')->
end()->
end()->
end()->
arrayNode('saucelabs')->
children()->
scalarNode('username')->
defaultValue(getenv('SAUCE_USERNAME'))->
end()->
scalarNode('access_key')->
defaultValue(getenv('SAUCE_ACCESS_KEY'))->
end()->
booleanNode('connect')->
defaultValue(isset($config['saucelabs']['connect']) ? 'true' === $config['saucelabs']['connect'] : false)->
end()->
scalarNode('browser')->
defaultValue(isset($config['saucelabs']['browser']) ? $config['saucelabs']['browser'] : 'firefox')->
end()->
arrayNode('capabilities')->
children()->
scalarNode('name')->
defaultValue(isset($config['saucelabs']['name']) ? $config['saucelabs']['name'] : 'Behat feature suite')->
end()->
scalarNode('platform')->
defaultValue(isset($config['saucelabs']['platform']) ? $config['saucelabs']['platform'] : 'Linux')->
end()->
scalarNode('version')->
defaultValue(isset($config['saucelabs']['version']) ? $config['saucelabs']['version'] : '21')->
end()->
scalarNode('deviceType')->
defaultValue(isset($config['saucelabs']['deviceType']) ? $config['saucelabs']['deviceType'] : null)->
end()->
scalarNode('deviceOrientation')->
defaultValue(isset($config['saucelabs']['deviceOrientation']) ? $config['saucelabs']['deviceOrientation'] : null)->
end()->
end()->
end()->
end()->
end()->
end()->
end();
})
->thenUnset()
->end()
->end()
->arrayNode('firefox')
->children()
->scalarNode('profile')
->validate()
->ifTrue(function ($v) {
return !file_exists($v);
})
->thenInvalid('Cannot find profile zip file %s')
->end()
->end()
->scalarNode('binary')->end()
->end()
->end()
->arrayNode('chrome')
->children()
->arrayNode('switches')->prototype('scalar')->end()->end()
->scalarNode('binary')->end()
->arrayNode('extensions')->prototype('scalar')->end()->end()
->end()
->end()
->end()
->end()
->scalarNode('wd_host')->defaultValue('http://localhost:4444/wd/hub')->end()
->end()
->end()
->arrayNode('saucelabs')
->children()
->scalarNode('username')->defaultValue(getenv('SAUCE_USERNAME'))->end()
->scalarNode('access_key')->defaultValue(getenv('SAUCE_ACCESS_KEY'))->end()
->booleanNode('connect')->defaultFalse()->end()
->scalarNode('browser')->defaultValue('firefox')->end()
->arrayNode('capabilities')
->addDefaultsIfNotSet()
->normalizeKeys(false)
->children()
->scalarNode('name')->defaultValue('Behat feature suite')->end()
->scalarNode('platform')->defaultValue('Linux')->end()
->scalarNode('version')->defaultValue('21')->end()
->scalarNode('selenium-version')->defaultValue('2.31.0')->end()
->scalarNode('max-duration')->defaultValue('300')->end()
->scalarNode('deviceType')->defaultNull()->end()
->scalarNode('deviceOrientation')->defaultNull()->end()
->end()
->end()
->end()
->end()
->end()
->end();
}
/**
@@ -415,21 +262,242 @@ class Extension implements BaseExtension
*/
public function process(ContainerBuilder $container)
{
$sessionsPass = new SessionsPass();
$selectorPass = new SelectorsPass();
$sessionsPass->process($container);
$selectorPass->process($container);
$this->processSessions($container);
$this->processSelectors($container);
}
protected function loadEnvironmentConfiguration()
private function loadMink(ContainerBuilder $container)
{
$config = array();
if ($envConfig = getenv('MINK_EXTENSION_PARAMS')) {
parse_str($envConfig, $config);
$container->setDefinition(self::MINK_ID, new Definition('Behat\Mink\Mink'));
}
private function loadContextInitializer(ContainerBuilder $container)
{
$definition = new Definition('Behat\MinkExtension\Context\Initializer\MinkAwareInitializer', array(
new Reference(self::MINK_ID),
'%mink.parameters%',
));
$definition->addTag(ContextExtension::INITIALIZER_TAG, array('priority' => 0));
$container->setDefinition('mink.context_initializer', $definition);
}
private function loadSelectorsHandler(ContainerBuilder $container)
{
$container->setDefinition(self::SELECTORS_HANDLER_ID, new Definition('Behat\Mink\Selector\SelectorsHandler'));
$cssSelectorDefinition = new Definition('Behat\Mink\Selector\CssSelector');
$cssSelectorDefinition->addTag(self::SELECTOR_TAG, array('alias' => 'css'));
$container->setDefinition(self::SELECTOR_TAG . '.css', $cssSelectorDefinition);
$namedSelectorDefinition = new Definition('Behat\Mink\Selector\NamedSelector');
$namedSelectorDefinition->addTag(self::SELECTOR_TAG, array('alias' => 'named'));
$container->setDefinition(self::SELECTOR_TAG . '.named', $namedSelectorDefinition);
}
private function loadSessionsListener(ContainerBuilder $container)
{
$definition = new Definition('Behat\MinkExtension\Listener\SessionsListener', array(
new Reference(self::MINK_ID),
'%mink.parameters%',
));
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, array('priority' => 0));
$container->setDefinition('mink.listener.sessions', $definition);
}
private function loadFailureShowListener(ContainerBuilder $container)
{
$definition = new Definition('Behat\MinkExtension\Listener\FailureShowListener', array(
new Reference(self::MINK_ID),
'%mink.parameters%',
));
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, array('priority' => 0));
$container->setDefinition('mink.listener.failure_show', $definition);
}
private function loadGoutteSession(ContainerBuilder $container, array $config)
{
if (!class_exists('Behat\Mink\Driver\GoutteDriver')) {
throw new \RuntimeException(
'Install MinkGoutteDriver in order to activate goutte session.'
);
}
return $config;
$clientDefinition = new Definition('Behat\Mink\Driver\Goutte\Client', array(
$config['server_parameters'],
));
$clientDefinition->addMethodCall('setClient', array(
new Definition('Guzzle\Http\Client', array(
null,
$config['guzzle_parameters'],
)),
));
$driverDefinition = new Definition('Behat\Mink\Driver\GoutteDriver', array(
$clientDefinition,
));
$this->loadSession($container, $driverDefinition, 'goutte');
}
}
private function loadSahiSession(ContainerBuilder $container, array $config)
{
if (!class_exists('Behat\Mink\Driver\SahiDriver')) {
throw new \RuntimeException(
'Install MinkSahiDriver in order to activate sahi session.'
);
}
$driverDefinition = new Definition('Behat\Mink\Driver\SahiDriver', array(
'%mink.browser_name%',
new Definition('Behat\SahiClient\Client', array(
new Definition('Behat\SahiClient\Connection', array(
$config['sid'],
$config['host'],
$config['port'],
$config['browser'],
$config['limit'],
)),
)),
));
$this->loadSession($container, $driverDefinition, 'sahi');
}
private function loadZombieSession(ContainerBuilder $container, array $config)
{
if (!class_exists('Behat\Mink\Driver\ZombieDriver')) {
throw new \RuntimeException(
'Install MinkZombieDriver in order to activate zombie session.'
);
}
$driverDefinition = new Definition('Behat\Mink\Driver\ZombieDriver', array(
new Definition('Behat\Mink\Driver\NodeJS\Server\ZombieServer', array(
$config['host'],
$config['port'],
$config['node_bin'],
$config['server_path'],
$config['threshold'],
$config['node_modules_path'],
)),
new Definition('Behat\Mink\Driver\NodeJS\Connection', array(
$config['host'],
$config['port'],
)),
$config['auto_server'],
));
$this->loadSession($container, $driverDefinition, 'zombie');
}
private function loadSeleniumSession(ContainerBuilder $container, array $config)
{
if (!class_exists('Behat\Mink\Driver\SeleniumDriver')) {
throw new \RuntimeException(
'Install MinkSeleniumDriver in order to activate selenium session.'
);
}
$driverDefinition = new Definition('Behat\Mink\Driver\SeleniumDriver', array(
$config['browser'],
'%mink.base_url%',
new Definition('Selenium\Client', array(
$config['host'],
$config['port'],
)),
));
$this->loadSession($container, $driverDefinition, 'selenium');
}
private function loadSelenium2Session(ContainerBuilder $container, array $config)
{
if (!class_exists('Behat\Mink\Driver\Selenium2Driver')) {
throw new \RuntimeException(
'Install MinkSelenium2Driver in order to activate selenium2 session.'
);
}
$driverDefinition = new Definition('Behat\Mink\Driver\Selenium2Driver', array(
$config['browser'],
$config['capabilities'],
$config['wd_host'],
));
$this->loadSession($container, $driverDefinition, 'selenium2');
}
private function loadSaucelabsSession(ContainerBuilder $container, array $config)
{
if (!class_exists('Behat\Mink\Driver\Selenium2Driver')) {
throw new \RuntimeException(
'Install MinkSelenium2Driver in order to activate saucelabs session.'
);
}
$capabilities = $config['capabilities'];
$capabilities['tags'] = array(php_uname('n'), 'PHP '.phpversion());
if (getenv('TRAVIS_JOB_NUMBER')) {
$capabilities['tunnel-identifier'] = getenv('TRAVIS_JOB_NUMBER');
$capabilities['build'] = getenv('TRAVIS_BUILD_NUMBER');
$capabilities['tags'] = array('Travis-CI', 'PHP '.phpversion());
}
$host = 'ondemand.saucelabs.com';
if ($config['connect']) {
$host = 'localhost:4445';
}
$driverDefinition = new Definition('Behat\Mink\Driver\Selenium2Driver', array(
$config['browser'],
$capabilities,
sprintf('%s:%s@%s/wd/hub', $config['username'], $config['access_key'], $host),
));
$this->loadSession($container, $driverDefinition, 'saucelabs');
}
private function loadSession(ContainerBuilder $container, Definition $driverDefinition, $alias)
{
$definition = new Definition('Behat\Mink\Session', array(
$driverDefinition,
new Reference(self::SELECTORS_HANDLER_ID),
));
$definition->addTag(self::SESSION_TAG, array('alias' => $alias));
$container->setDefinition(self::SESSION_TAG . '.' . $alias, $definition);
}
private function processSessions(ContainerBuilder $container)
{
$handlerDefinition = $container->getDefinition(self::MINK_ID);
foreach ($container->findTaggedServiceIds(self::SESSION_TAG) as $id => $tags) {
foreach ($tags as $tag) {
if (!isset($tag['alias'])) {
throw new ProcessingException(sprintf(
'All `%s` tags should have an `alias` attribute, but `%s` service has none.',
$tag,
$id
));
}
$handlerDefinition->addMethodCall(
'registerSession', array($tag['alias'], new Reference($id))
);
}
}
}
private function processSelectors(ContainerBuilder $container)
{
$handlerDefinition = $container->getDefinition(self::SELECTORS_HANDLER_ID);
foreach ($container->findTaggedServiceIds(self::SELECTOR_TAG) as $id => $tags) {
foreach ($tags as $tag) {
if (!isset($tag['alias'])) {
throw new ProcessingException(sprintf(
'All `%s` tags should have an `alias` attribute, but `%s` service has none.',
$tag,
$id
));
}
$handlerDefinition->addMethodCall(
'registerSelector', array($tag['alias'], new Reference($id))
);
}
}
}
}

View File

@@ -1,22 +1,21 @@
<?php
namespace Behat\MinkExtension\Listener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Behat\Behat\Event\StepEvent;
use Behat\Mink\Mink;
use Behat\Mink\Exception\Exception as MinkException;
/*
* This file is part of the Behat\MinkExtension.
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Listener;
use Behat\Behat\Tester\Event\StepTested;
use Behat\Testwork\Tester\Result\TestResult;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Behat\Mink\Mink;
use Behat\Mink\Exception\Exception as MinkException;
/**
* Failed step response show listener.
* Listens to failed Behat steps and shows last response in a browser.
@@ -41,27 +40,12 @@ class FailureShowListener implements EventSubscriberInterface
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
'afterStep' => array('showFailedStepResponse', -10)
StepTested::AFTER => array('showFailedStepResponse', -10)
);
}
@@ -73,15 +57,15 @@ class FailureShowListener implements EventSubscriberInterface
* `show_cmd` command to run (`open %s` to open default browser on Mac)
* `show_tmp_dir` folder where to store temp files (default is system temp)
*
* @param StepEvent $event
* @param StepTested $event
*/
public function showFailedStepResponse($event)
public function showFailedStepResponse(StepTested $event)
{
if (StepEvent::FAILED !== $event->getResult()) {
if (TestResult::FAILED !== $event->getResultCode()) {
return;
}
if (!$event->getException() instanceof MinkException) {
if (!$event->getTestResult()->getException() instanceof MinkException) {
return;
}

View File

@@ -1,22 +1,22 @@
<?php
namespace Behat\MinkExtension\Listener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Behat\Behat\Event\ScenarioEvent,
Behat\Behat\Event\OutlineEvent;
use Behat\Mink\Mink;
/*
* This file is part of the Behat\MinkExtension.
* This file is part of the Behat MinkExtension.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\MinkExtension\Listener;
use Behat\Behat\Tester\Event\AbstractScenarioTested;
use Behat\Behat\Tester\Event\ExampleTested;
use Behat\Behat\Tester\Event\ScenarioTested;
use Behat\Mink\Mink;
use Behat\Testwork\Tester\Event\ExerciseCompleted;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Mink sessions listener.
* Listens Behat events and configures/stops Mink sessions.
@@ -41,29 +41,14 @@ class SessionsListener implements EventSubscriberInterface
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
'beforeScenario' => array('prepareDefaultMinkSession', 10),
'beforeOutlineExample' => array('prepareDefaultMinkSession', 10),
'afterSuite' => array('tearDownMinkSessions', -10)
ScenarioTested::BEFORE => array('prepareDefaultMinkSession', 10),
ExampleTested::BEFORE => array('prepareDefaultMinkSession', 10),
ExerciseCompleted::AFTER => array('tearDownMinkSessions', -10)
);
}
@@ -78,14 +63,15 @@ class SessionsListener implements EventSubscriberInterface
* `@insulated` tag will cause Mink to stop current sessions before scenario
* instead of just soft-resetting them
*
* @param ScenarioEvent|OutlineExampleEvent $event
* @param AbstractScenarioTested $event
*/
public function prepareDefaultMinkSession($event)
public function prepareDefaultMinkSession(AbstractScenarioTested $event)
{
$scenario = $event instanceof ScenarioEvent ? $event->getScenario() : $event->getOutline();
$scenario = $event->getScenario();
$feature = $event->getFeature();
$session = $this->parameters['default_session'];
foreach ($scenario->getTags() as $tag) {
foreach (array_merge($feature->getTags(), $scenario->getTags()) as $tag) {
if ('javascript' === $tag) {
$session = $this->parameters['javascript_session'];
} elseif (preg_match('/^mink\:(.+)/', $tag, $matches)) {
@@ -93,7 +79,7 @@ class SessionsListener implements EventSubscriberInterface
}
}
if ($scenario->hasTag('insulated')) {
if ($scenario->hasTag('insulated') || $feature->hasTag('insulated')) {
$this->mink->stopSessions();
} else {
$this->mink->resetSessions();

View File

@@ -1,56 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="mink.paths.lib">null</parameter>
<parameter key="behat.mink.parameters" type="collection"></parameter>
<parameter key="behat.mink.class">Behat\Mink\Mink</parameter>
<parameter key="behat.mink.session.class">Behat\Mink\Session</parameter>
<parameter key="behat.mink.selector.handler.class">Behat\Mink\Selector\SelectorsHandler</parameter>
<parameter key="behat.mink.selector.css.class">Behat\Mink\Selector\CssSelector</parameter>
<parameter key="behat.mink.selector.named.class">Behat\Mink\Selector\NamedSelector</parameter>
<parameter key="behat.mink.context.class_guesser.class">Behat\MinkExtension\Context\ClassGuesser\MinkContextClassGuesser</parameter>
<parameter key="behat.mink.context.initializer.class">Behat\MinkExtension\Context\Initializer\MinkAwareInitializer</parameter>
<parameter key="behat.mink.listener.sessions_listener.class">Behat\MinkExtension\Listener\SessionsListener</parameter>
<parameter key="behat.mink.default_session">goutte</parameter>
<parameter key="behat.mink.javascript_session">selenium2</parameter>
<parameter key="behat.mink.base_url">null</parameter>
<parameter key="behat.mink.show_cmd">null</parameter>
<parameter key="behat.mink.show_tmp_dir">null</parameter>
<parameter key="behat.mink.browser_name">firefox</parameter>
</parameters>
<services>
<service id="behat.mink" class="%behat.mink.class%" />
<service id="behat.mink.selector.handler" class="%behat.mink.selector.handler.class%" />
<service id="behat.mink.selector.css" class="%behat.mink.selector.css.class%">
<tag name="behat.mink.selector" alias="css" />
</service>
<service id="behat.mink.selector.named" class="%behat.mink.selector.named.class%">
<tag name="behat.mink.selector" alias="named" />
</service>
<service id="behat.mink.context.class_guesser" class="%behat.mink.context.class_guesser.class%">
<tag name="behat.context.class_guesser" priority="0" />
</service>
<service id="behat.mink.context.initializer" class="%behat.mink.context.initializer.class%">
<argument type="service" id="behat.mink" />
<argument>%behat.mink.parameters%</argument>
<tag name="context.initializer" priority="0" />
</service>
<service id="behat.mink.listener.sessions_listener" class="%behat.mink.listener.sessions_listener.class%">
<argument type="service" id="behat.mink" />
<argument>%behat.mink.parameters%</argument>
<tag name="behat.event_subscriber" priority="0" />
</service>
</services>
</container>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.listener.failure_show_listener.class">Behat\MinkExtension\Listener\FailureShowListener</parameter>
</parameters>
<services>
<service id="behat.mink.listener.failure_show_listener" class="%behat.mink.listener.failure_show_listener.class%">
<argument type="service" id="behat.mink" />
<argument>%behat.mink.parameters%</argument>
<tag name="behat.event_subscriber" priority="0" />
</service>
</services>
</container>

View File

@@ -1,39 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.driver.goutte.class">Behat\Mink\Driver\GoutteDriver</parameter>
<parameter key="behat.mink.goutte.class">Behat\Mink\Driver\Goutte\Client</parameter>
<parameter key="behat.mink.guzzle.class">Guzzle\Http\Client</parameter>
<parameter key="behat.mink.goutte.server_parameters" type="collection"></parameter>
<parameter key="behat.mink.goutte.guzzle_parameters" type="collection"></parameter>
</parameters>
<services>
<service id="behat.mink.session.goutte" class="%behat.mink.session.class%">
<argument type="service">
<service class="%behat.mink.driver.goutte.class%">
<argument type="service" id="behat.mink.goutte" />
</service>
</argument>
<argument type="service" id="behat.mink.selector.handler" />
<tag name="behat.mink.session" alias="goutte" />
</service>
<service id="behat.mink.goutte" class="%behat.mink.goutte.class%">
<argument>%behat.mink.goutte.server_parameters%</argument>
<call method="setClient">
<argument type="service" id="behat.mink.guzzle" />
</call>
</service>
<service id="behat.mink.guzzle" class="%behat.mink.guzzle.class%">
<argument>null</argument>
<argument>%behat.mink.goutte.guzzle_parameters%</argument>
</service>
</services>
</container>

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.driver.sahi.class">Behat\Mink\Driver\SahiDriver</parameter>
<parameter key="behat.mink.sahi.class">Behat\SahiClient\Client</parameter>
<parameter key="behat.mink.sahi.connection.class">Behat\SahiClient\Connection</parameter>
<parameter key="behat.mink.sahi.sid">null</parameter>
<parameter key="behat.mink.sahi.host">localhost</parameter>
<parameter key="behat.mink.sahi.port">9999</parameter>
<parameter key="behat.mink.sahi.browser">null</parameter>
<parameter key="behat.mink.sahi.limit">600</parameter>
</parameters>
<services>
<service id="behat.mink.session.sahi" class="%behat.mink.session.class%">
<argument type="service">
<service class="%behat.mink.driver.sahi.class%">
<argument>%behat.mink.browser_name%</argument>
<argument type="service" id="behat.mink.sahi" />
</service>
</argument>
<argument type="service" id="behat.mink.selector.handler" />
<tag name="behat.mink.session" alias="sahi" />
</service>
<service id="behat.mink.sahi" class="%behat.mink.sahi.class%">
<argument type="service">
<service class="%behat.mink.sahi.connection.class%">
<argument>%behat.mink.sahi.sid%</argument>
<argument>%behat.mink.sahi.host%</argument>
<argument>%behat.mink.sahi.port%</argument>
<argument>%behat.mink.sahi.browser%</argument>
<argument>%behat.mink.sahi.limit%</argument>
</service>
</argument>
</service>
</services>
</container>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.driver.saucelabs.class">Behat\Mink\Driver\Selenium2Driver</parameter>
<parameter key="behat.mink.saucelabs.browser">%behat.mink.browser_name%</parameter>
<parameter key="behat.mink.saucelabs.capabilities" type="collection">
<parameter key="name" type="string">Behat feature suite</parameter>
<parameter key="version" type="string">21</parameter>
<parameter key="platform" type="string">Linux</parameter>
<parameter key="selenium-version" type="string">2.31.0</parameter>
<parameter key="max-duration">300</parameter>
</parameter>
<parameter key="behat.mink.saucelabs.wd_host">https://USERNAME:ACCESS_KEY@ondemand.saucelabs.com/wd/hub</parameter>
</parameters>
<services>
<service id="behat.mink.session.saucelabs" class="%behat.mink.session.class%">
<argument type="service">
<service class="%behat.mink.driver.saucelabs.class%">
<argument>%behat.mink.saucelabs.browser%</argument>
<argument>%behat.mink.saucelabs.capabilities%</argument>
<argument>%behat.mink.saucelabs.wd_host%</argument>
</service>
</argument>
<argument type="service" id="behat.mink.selector.handler" />
<tag name="behat.mink.session" alias="saucelabs" />
</service>
</services>
</container>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.driver.selenium.class">Behat\Mink\Driver\SeleniumDriver</parameter>
<parameter key="behat.mink.selenium.class">Selenium\Client</parameter>
<parameter key="behat.mink.selenium.host">127.0.0.1</parameter>
<parameter key="behat.mink.selenium.port">4444</parameter>
<parameter key="behat.mink.selenium.browser">*%behat.mink.browser_name%</parameter>
</parameters>
<services>
<service id="behat.mink.session.selenium" class="%behat.mink.session.class%">
<argument type="service">
<service class="%behat.mink.driver.selenium.class%">
<argument>%behat.mink.selenium.browser%</argument>
<argument>%behat.mink.base_url%</argument>
<argument type="service" id="behat.mink.selenium" />
</service>
</argument>
<argument type="service" id="behat.mink.selector.handler" />
<tag name="behat.mink.session" alias="selenium" />
</service>
<service id="behat.mink.selenium" class="%behat.mink.selenium.class%">
<argument>%behat.mink.selenium.host%</argument>
<argument>%behat.mink.selenium.port%</argument>
</service>
</services>
</container>

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.driver.selenium2.class">Behat\Mink\Driver\Selenium2Driver</parameter>
<parameter key="behat.mink.selenium2.browser">%behat.mink.browser_name%</parameter>
<parameter key="behat.mink.selenium2.capabilities" type="collection">
<parameter key="browserName" type="string">firefox</parameter>
<parameter key="version" type="string">8</parameter>
<parameter key="platform" type="string">ANY</parameter>
<parameter key="browserVersion" type="string">8</parameter>
<parameter key="browser" type="string">firefox</parameter>
<parameter key="name" type="string">Behat test</parameter>
<parameter key="deviceOrientation" type="string">portrait</parameter>
<parameter key="deviceType" type="string">tablet</parameter>
<parameter key="selenium-version" type="string">2.31.0</parameter>
<parameter key="max-duration">300</parameter>
</parameter>
<parameter key="behat.mink.selenium2.wd_host">http://localhost:4444/wd/hub</parameter>
</parameters>
<services>
<service id="behat.mink.session.selenium2" class="%behat.mink.session.class%">
<argument type="service">
<service class="%behat.mink.driver.selenium2.class%">
<argument>%behat.mink.selenium2.browser%</argument>
<argument>%behat.mink.selenium2.capabilities%</argument>
<argument>%behat.mink.selenium2.wd_host%</argument>
</service>
</argument>
<argument type="service" id="behat.mink.selector.handler" />
<tag name="behat.mink.session" alias="selenium2" />
</service>
</services>
</container>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.mink.driver.zombie.class">Behat\Mink\Driver\ZombieDriver</parameter>
<parameter key="behat.mink.zombie.connection.class">Behat\Mink\Driver\NodeJS\Connection</parameter>
<parameter key="behat.mink.zombie.server.class">Behat\Mink\Driver\NodeJS\Server\ZombieServer</parameter>
<parameter key="behat.mink.zombie.host">127.0.0.1</parameter>
<parameter key="behat.mink.zombie.port">8124</parameter>
<parameter key="behat.mink.zombie.auto_server">true</parameter>
<parameter key="behat.mink.zombie.node_bin">node</parameter>
<parameter key="behat.mink.zombie.server_path">null</parameter>
<parameter key="behat.mink.zombie.threshold">2000000</parameter>
<parameter key="behat.mink.zombie.node_modules_path"></parameter>
</parameters>
<services>
<service id="behat.mink.session.zombie" class="%behat.mink.session.class%">
<argument type="service">
<service class="%behat.mink.driver.zombie.class%">
<argument type="service" id="behat.mink.zombie.server" />
<argument type="service" id="behat.mink.zombie.connection" />
<argument>%behat.mink.zombie.auto_server%</argument>
</service>
</argument>
<argument type="service" id="behat.mink.selector.handler" />
<tag name="behat.mink.session" alias="zombie" />
</service>
<service id="behat.mink.zombie.connection" class="%behat.mink.zombie.connection.class%">
<argument>%behat.mink.zombie.host%</argument>
<argument>%behat.mink.zombie.port%</argument>
</service>
<service id="behat.mink.zombie.server" class="%behat.mink.zombie.server.class%">
<argument>%behat.mink.zombie.host%</argument>
<argument>%behat.mink.zombie.port%</argument>
<argument>%behat.mink.zombie.node_bin%</argument>
<argument>%behat.mink.zombie.server_path%</argument>
<argument>%behat.mink.zombie.threshold%</argument>
<argument>%behat.mink.zombie.node_modules_path%</argument>
</service>
</services>
</container>