Skip to content

Instantly share code, notes, and snippets.

@gggeek
Last active August 29, 2015 14:10
Show Gist options
  • Save gggeek/f7a27006b9861ec841b9 to your computer and use it in GitHub Desktop.
Save gggeek/f7a27006b9861ec841b9 to your computer and use it in GitHub Desktop.
POC: implement cross-context communication for Behat-3
default:
extensions:
Kaliop\Behat\KToolsExtension: ~
<?php
namespace Kaliop\Behat\KToolsExtension\Listener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Behat\Behat\EventDispatcher\Event\ScenarioTested;
use Behat\Behat\EventDispatcher\Event\OutlineTested;
use Behat\Behat\EventDispatcher\Event\ScenarioLikeTested;
use Kaliop\Behat\KToolsExtension\Context\SharedContext;
/**
* Will hold all the necessary event listeners
*/
class EventListener implements EventSubscriberInterface
{
protected $sharedContext;
/**
* @param SharedContext $sharedContext
*/
public function __construct($sharedContext)
{
$this->sharedContext = $sharedContext;
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
return array(
// these we call after either a single scenario or a scenario-with-examples has finished
ScenarioTested::BEFORE_TEARDOWN => array('resetSharedContexts', -10),
OutlineTested::BEFORE_TEARDOWN => array('resetSharedContexts', -10),
);
}
public function resetSharedContexts()
{
$this->sharedContext->resetContexts();
}
}
parameters:
kaliop.ktools_extension.context.initializer.class: Kaliop\Behat\KToolsExtension\Context\Initializer\ShareableContextInitializer
kaliop.ktools_extension.sharedcontext.container.class: Kaliop\Behat\KToolsExtension\Context\SharedContextContainer
kaliop.ktools_extension.event.listener.class: Kaliop\Behat\KToolsExtension\Listener\EventListener
services:
kaliop.ktools_extension.sharedcontext.container:
class: "%kaliop.ktools_extension.sharedcontext.container.class%"
kaliop.ktools_extension.context.initializer:
class: "%kaliop.ktools_extension.context.initializer.class%"
arguments: [@kaliop.ktools_extension.sharedcontext.container]
tags:
- { name: context.initializer }
kaliop.ktools_extension.event.listener:
class: "%kaliop.ktools_extension.event.listener.class%"
arguments: [@kaliop.ktools_extension.sharedcontext.container]
tags:
- { name: event_dispatcher.subscriber }
<?php
namespace Kaliop\Behat\KToolsExtension\Context;
interface ShareableContext
{
/**
* @param callable $shareCallable
*
* Implementors just need to execute call_user_func($shareCallable, $this);
*/
public function shareContext($shareCallable);
}
<?php
namespace Kaliop\Behat\KToolsExtension\Context\Initializer;
use Behat\Behat\Context\Context;
use Behat\Behat\Context\Initializer\ContextInitializer;
use Kaliop\Behat\KToolsExtension\Context\ShareableContext;
use Kaliop\Behat\KToolsExtension\Context\SharedContextAwareContext;
class ShareableContextInitializer implements ContextInitializer
{
protected $sharedContextContainer = null;
/**
* @param $sharedContextContainer
*/
public function __construct($sharedContextContainer)
{
$this->sharedContextContainer = $sharedContextContainer;
}
/**
* @param Context $context
*/
public function initializeContext(Context $context)
{
if ($context instanceof ShareableContext) {
$context->shareContext(array($this->sharedContextContainer, 'shareContext'));
}
if ($context instanceof SharedContextAwareContext) {
$context->setSharedContextContainer($this->sharedContextContainer);
}
}
}
<?php
namespace Kaliop\Behat\KToolsExtension\Context;
use Kaliop\Behat\KToolsExtension\Context\SharedContextContainer;
interface SharedContextAwareContext
{
/**
* @param SharedContextContainer $sharedContextContainer
*/
public function setSharedContextContainer($sharedContextContainer);
}
<?php
namespace Kaliop\Behat\KToolsExtension\Context;
use Behat\Behat\Context\Context;
/**
* Implements a 'singleton' pattern to allow communication between the different Contexts in a feature.
* In practice this class will hold instances of contexts - one instance per class.
* Contexts who want to be shared just need to implement the ShareableContext interface.
* To grab a hold on an instance of this class, use an appropriate Symfony service
*
* @todo implement an interface
* @todo allow usage of fully qualified classnames as context identifiers (based eg. on a bool flag passed to constructor)
*/
class SharedContextContainer
{
protected static $contexts = array();
public function shareContext(Context $context)
{
$className = get_class($context);
$className = end(explode('\\', $className));
static::$contexts[$className] = $context;
}
/**
* @param string $name name (class) of context
* @return Context
*/
public function getContext($name)
{
if(!isset(static::$contexts[$name]))
throw new \RuntimeException("No context of type '$name' has been shared");
return static::$contexts[$name];
}
public function resetContexts()
{
static::$contexts = array();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment