303 lines
12 KiB
PHP
303 lines
12 KiB
PHP
<?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\Behat\Context\ServiceContainer\ContextExtension;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\GoutteFactory;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\SahiFactory;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\SaucelabsFactory;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\Selenium2Factory;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\SeleniumFactory;
|
|
use Behat\MinkExtension\ServiceContainer\Driver\ZombieFactory;
|
|
use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension;
|
|
use Behat\Testwork\ServiceContainer\Exception\ProcessingException;
|
|
use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface;
|
|
use Behat\Testwork\ServiceContainer\ExtensionManager;
|
|
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
|
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
|
use Symfony\Component\DependencyInjection\Definition;
|
|
use Symfony\Component\DependencyInjection\Reference;
|
|
|
|
/**
|
|
* Mink extension for Behat class.
|
|
*
|
|
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
|
*/
|
|
class Extension implements ExtensionInterface
|
|
{
|
|
const MINK_ID = 'mink';
|
|
const SELECTORS_HANDLER_ID = 'mink.selectors_handler';
|
|
|
|
const SELECTOR_TAG = 'mink.selector';
|
|
|
|
/**
|
|
* @var DriverFactory[]
|
|
*/
|
|
private $driverFactories = array();
|
|
|
|
public function __construct()
|
|
{
|
|
$this->registerDriverFactory(new GoutteFactory());
|
|
$this->registerDriverFactory(new SahiFactory());
|
|
$this->registerDriverFactory(new SeleniumFactory());
|
|
$this->registerDriverFactory(new Selenium2Factory());
|
|
$this->registerDriverFactory(new SaucelabsFactory());
|
|
$this->registerDriverFactory(new ZombieFactory());
|
|
}
|
|
|
|
public function registerDriverFactory(DriverFactory $driverFactory)
|
|
{
|
|
$this->driverFactories[$driverFactory->getDriverName()] = $driverFactory;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function load(ContainerBuilder $container, array $config)
|
|
{
|
|
if (isset($config['mink_loader'])) {
|
|
$basePath = $container->getParameter('paths.base');
|
|
|
|
if (file_exists($basePath.DIRECTORY_SEPARATOR.$config['mink_loader'])) {
|
|
require($basePath.DIRECTORY_SEPARATOR.$config['mink_loader']);
|
|
} else {
|
|
require($config['mink_loader']);
|
|
}
|
|
}
|
|
|
|
$this->loadMink($container);
|
|
$this->loadContextInitializer($container);
|
|
$this->loadSelectorsHandler($container);
|
|
$this->loadSessions($container, $config);
|
|
$this->loadSessionsListener($container);
|
|
|
|
if ($config['show_auto']) {
|
|
$this->loadFailureShowListener($container);
|
|
}
|
|
|
|
unset($config['sessions']);
|
|
|
|
$container->setParameter('mink.parameters', $config);
|
|
$container->setParameter('mink.base_url', $config['base_url']);
|
|
$container->setParameter('mink.browser_name', $config['browser_name']);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function configure(ArrayNodeDefinition $builder)
|
|
{
|
|
// Rewrite keys to define a shortcut way without allowing conflicts with real keys
|
|
$renamedKeys = array_diff(
|
|
array_keys($this->driverFactories),
|
|
array('mink_loader', 'base_url', 'files_path', 'show_auto', 'show_cmd', 'show_tmp_dir', 'default_session', 'javascript_session', 'browser_name', 'sessions')
|
|
);
|
|
|
|
$builder
|
|
->beforeNormalization()
|
|
->always()
|
|
->then(function ($v) use ($renamedKeys) {
|
|
foreach ($renamedKeys as $driverType) {
|
|
if (!array_key_exists($driverType, $v) || isset($v['sessions'][$driverType])) {
|
|
continue;
|
|
}
|
|
|
|
$v['sessions'][$driverType][$driverType] = $v[$driverType];
|
|
unset($v[$driverType]);
|
|
}
|
|
|
|
return $v;
|
|
})
|
|
->end()
|
|
->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')->defaultNull()->info('Defaults to the first non-javascript session if any, or the first session otherwise')->end()
|
|
->scalarNode('javascript_session')->defaultNull()->info('Defaults to the first javascript session if any')->end()
|
|
->scalarNode('browser_name')->defaultValue('firefox')->end()
|
|
->end()
|
|
->end();
|
|
|
|
/** @var ArrayNodeDefinition $sessionsBuilder */
|
|
$sessionsBuilder = $builder
|
|
->children()
|
|
->arrayNode('sessions')
|
|
->isRequired()
|
|
->requiresAtLeastOneElement()
|
|
->useAttributeAsKey('name')
|
|
->prototype('array')
|
|
;
|
|
|
|
foreach ($this->driverFactories as $factory) {
|
|
$factoryNode = $sessionsBuilder->children()->arrayNode($factory->getDriverName())->canBeUnset();
|
|
|
|
$factory->configure($factoryNode);
|
|
}
|
|
|
|
$sessionsBuilder
|
|
->validate()
|
|
->ifTrue(function ($v) {return count($v) > 1;})
|
|
->thenInvalid('You cannot set multiple driver types for the same session')
|
|
->end()
|
|
->validate()
|
|
->ifTrue(function ($v) {return count($v) === 0;})
|
|
->thenInvalid('You must set a driver definition for the session.')
|
|
->end()
|
|
;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function getConfigKey()
|
|
{
|
|
return 'mink';
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function initialize(ExtensionManager $extensionManager)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function process(ContainerBuilder $container)
|
|
{
|
|
$this->processSelectors($container);
|
|
}
|
|
|
|
private function loadMink(ContainerBuilder $container)
|
|
{
|
|
$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 loadSessions(ContainerBuilder $container, array $config)
|
|
{
|
|
$defaultSession = $config['default_session'];
|
|
$javascriptSession = $config['javascript_session'];
|
|
$javascriptSessions = $nonJavascriptSessions = array();
|
|
|
|
$minkDefinition = $container->getDefinition(self::MINK_ID);
|
|
|
|
foreach ($config['sessions'] as $name => $session) {
|
|
$driver = key($session);
|
|
$factory = $this->driverFactories[$driver];
|
|
|
|
$definition = new Definition('Behat\Mink\Session', array(
|
|
$factory->buildDriver($session[$driver]),
|
|
new Reference(self::SELECTORS_HANDLER_ID),
|
|
));
|
|
$minkDefinition->addMethodCall('registerSession', array($name, $definition));
|
|
|
|
if ($factory->supportsJavascript()) {
|
|
$javascriptSessions[] = $name;
|
|
} else {
|
|
$nonJavascriptSessions[] = $name;
|
|
}
|
|
}
|
|
|
|
if (null === $javascriptSession && !empty($javascriptSessions)) {
|
|
$javascriptSession = $javascriptSessions[0];
|
|
} elseif (null !== $javascriptSession && !in_array($javascriptSession, $javascriptSessions)) {
|
|
throw new InvalidConfigurationException(sprintf(
|
|
'The javascript session must be one of the enabled javascript sessions (%s), but got %s',
|
|
json_encode($javascriptSessions),
|
|
$javascriptSession
|
|
));
|
|
}
|
|
|
|
if (null === $defaultSession) {
|
|
$defaultSession = !empty($nonJavascriptSessions) ? $nonJavascriptSessions[0] : $javascriptSessions[0];
|
|
} elseif (!isset($config['sessions'][$defaultSession])) {
|
|
throw new InvalidConfigurationException(sprintf('The default session must be one of the enabled sessions, but got %s', $defaultSession));
|
|
}
|
|
|
|
$container->setParameter('mink.default_session', $defaultSession);
|
|
$container->setParameter('mink.javascript_session', $javascriptSession);
|
|
$container->setParameter('mink.available_javascript_sessions', $javascriptSessions);
|
|
}
|
|
|
|
private function loadSessionsListener(ContainerBuilder $container)
|
|
{
|
|
$definition = new Definition('Behat\MinkExtension\Listener\SessionsListener', array(
|
|
new Reference(self::MINK_ID),
|
|
'%mink.default_session%',
|
|
'%mink.javascript_session%',
|
|
'%mink.available_javascript_sessions%',
|
|
));
|
|
$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 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))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|