mirror of
https://github.com/silverstripe/silverstripe-behat-extension
synced 2024-10-22 17:05:32 +02:00
NEW Reduced boilerplate configuration
- Moved all extension-specific conf into its own configuration namespace - Described configuration via PHP, and added default values - Removed boilerplate config from README - Made screenshot_path optional - Configurable ajax_timeout settings Note: The DI system plus the initializer+context combo requires insane amounts of code duplication, will need to be looked at more closely (very little docs on that level of Behat extension available).
This commit is contained in:
parent
66a07442cf
commit
38a27d2a50
39
README.md
39
README.md
@ -102,46 +102,37 @@ Example: behat.yml
|
||||
|
||||
default:
|
||||
context:
|
||||
parameters:
|
||||
admin_url: /admin/
|
||||
login_url: /Security/login
|
||||
screenshot_path: %behat.paths.features%/screenshots/
|
||||
class: SilverStripe\MyModule\Test\Behaviour\FeatureContext
|
||||
extensions:
|
||||
SilverStripe\BehatExtension\Extension:
|
||||
# Assumes path relative to vendor/silverstripe/silverstripe-behat
|
||||
framework_path: ../../../framework/
|
||||
ajax_steps:
|
||||
- go to
|
||||
- follow
|
||||
- press
|
||||
- click
|
||||
- submit
|
||||
SilverStripe\BehatExtension\Extension: ~
|
||||
Behat\MinkExtension\Extension:
|
||||
# Adjust this to your local environment
|
||||
base_url: http://localhost/
|
||||
files_path: %behat.paths.features%/files/
|
||||
default_session: selenium2
|
||||
javascript_session: selenium2
|
||||
goutte: ~
|
||||
selenium2:
|
||||
browser: firefox
|
||||
|
||||
Here's an overview of the non-stndard settings we've added.
|
||||
You'll need to customize at least the `framework_path` and `base_url` setting.
|
||||
You'll need to customize at least the `base_url` setting to match the URL where
|
||||
the tested SilverStripe instance is hosted locally.
|
||||
Overview of settings (all in the `extensions.SilverStripe\BehatExtension\Extension` path):
|
||||
|
||||
* `default.context.parameters.screenshot_path`: Used to store screenshot of a last known state
|
||||
of a failed step. It defaults to whatever is returned by PHP's `sys_get_temp_dir()`.
|
||||
Screenshot names within that directory consist of feature file filename and line
|
||||
number that failed.
|
||||
* `default.extensions.SilverStripe\BehatExtension\Extension.framework_path`: Path to the SilverStripe Framework folder. It supports both absolute and relative (to `behat.yml` file) paths.
|
||||
* `default.extensions.Behat\MinkExtension\Extension.base_url`: You will probably need to change the base URL that is used during the test process.
|
||||
* `framework_path`: Path to the SilverStripe Framework folder. It supports both absolute and relative (to `behat.yml` file) paths.
|
||||
* `extensions.Behat\MinkExtension\Extension.base_url`: You will probably need to change the base URL that is used during the test process.
|
||||
It is used every time you use relative URLs in your feature descriptions.
|
||||
It will also be used by [file to URL mapping](http://doc.silverstripe.org/framework/en/topics/commandline#configuration) in `SilverStripeExtension`.
|
||||
* `default.extensions.Behat\MinkExtension\Extension.files_path`: Change to support file uploads in your tests. Currently only absolute paths are supported.
|
||||
* `default.extensions.SilverStripe\BehatExtension\Extension.ajax_steps`: Because SilverStripe uses AJAX requests quite extensively, we had to invent a way
|
||||
* `extensions.Behat\MinkExtension\Extension.files_path`: Change to support file uploads in your tests. Currently only absolute paths are supported.
|
||||
* `ajax_steps`: Because SilverStripe uses AJAX requests quite extensively, we had to invent a way
|
||||
to deal with them more efficiently and less verbose than just
|
||||
Optional `ajax_steps` is used to match steps defined there so they can be "caught" by
|
||||
[special AJAX handlers](http://blog.scur.pl/2012/06/ajax-callback-support-behat-mink/) that tweak the delays. You can either use a pipe delimited string or a list of substrings that match step definition.
|
||||
* `ajax_timeout`: Milliseconds after which an Ajax request is regarded as timed out,
|
||||
and the script continues with its assertions to avoid a deadlock (Default: 5000).
|
||||
* `screenshot_path`: Used to store screenshot of a last known state
|
||||
of a failed step. It defaults to whatever is returned by PHP's `sys_get_temp_dir()`.
|
||||
Screenshot names within that directory consist of feature file filename and line
|
||||
number that failed.
|
||||
|
||||
### Additional profiles
|
||||
|
||||
|
@ -107,7 +107,7 @@ JS;
|
||||
*/
|
||||
public function handleAjaxBeforeStep(StepEvent $event)
|
||||
{
|
||||
$ajax_enabled_steps = $this->getMainContext()->getAjaxEnabledSteps();
|
||||
$ajax_enabled_steps = $this->getMainContext()->getAjaxSteps();
|
||||
$ajax_enabled_steps = implode('|', array_filter($ajax_enabled_steps));
|
||||
|
||||
if (empty($ajax_enabled_steps) || !preg_match('/(' . $ajax_enabled_steps . ')/i', $event->getStep()->getText())) {
|
||||
@ -150,7 +150,7 @@ JS;
|
||||
*/
|
||||
public function handleAjaxAfterStep(StepEvent $event)
|
||||
{
|
||||
$ajax_enabled_steps = $this->getMainContext()->getAjaxEnabledSteps();
|
||||
$ajax_enabled_steps = $this->getMainContext()->getAjaxSteps();
|
||||
$ajax_enabled_steps = implode('|', array_filter($ajax_enabled_steps));
|
||||
|
||||
if (empty($ajax_enabled_steps) || !preg_match('/(' . $ajax_enabled_steps . ')/i', $event->getStep()->getText())) {
|
||||
@ -171,8 +171,10 @@ JS;
|
||||
|
||||
public function handleAjaxTimeout()
|
||||
{
|
||||
$timeoutMs = $this->getMainContext()->getAjaxTimeout();
|
||||
|
||||
// Wait for an ajax request to complete, but only for a maximum of 5 seconds to avoid deadlocks
|
||||
$this->getSession()->wait(5000,
|
||||
$this->getSession()->wait($timeoutMs,
|
||||
"(typeof window.__ajaxStatus !== 'undefined' ? window.__ajaxStatus() : 'no ajax') !== 'waiting'"
|
||||
);
|
||||
|
||||
@ -205,35 +207,33 @@ JS;
|
||||
$step = $event->getStep();
|
||||
$screenshot_path = null;
|
||||
|
||||
if (isset($this->context['screenshot_path'])) {
|
||||
$screenshot_path = realpath($this->context['screenshot_path']);
|
||||
if (!$screenshot_path) {
|
||||
$path = $this->getMainContext()->getScreenshotPath();
|
||||
if(!$path) return; // quit silently when path is not set
|
||||
|
||||
$path = realpath($path);
|
||||
if (!$path) {
|
||||
\Filesystem::makeFolder($this->context['screenshot_path']);
|
||||
$screenshot_path = realpath($this->context['screenshot_path']);
|
||||
}
|
||||
}
|
||||
if (!$screenshot_path) {
|
||||
$screenshot_path = realpath(sys_get_temp_dir());
|
||||
$path = realpath($this->context['screenshot_path']);
|
||||
}
|
||||
|
||||
if (!file_exists($screenshot_path)) {
|
||||
if (!file_exists($path)) {
|
||||
file_put_contents('php://stderr', sprintf('"%s" is not valid directory and failed to create it' . PHP_EOL, $this->context['screenshot_path']));
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_exists($screenshot_path) && !is_dir($screenshot_path)) {
|
||||
if (file_exists($path) && !is_dir($path)) {
|
||||
file_put_contents('php://stderr', sprintf('"%s" is not valid directory' . PHP_EOL, $this->context['screenshot_path']));
|
||||
return;
|
||||
}
|
||||
if (file_exists($screenshot_path) && !is_writable($screenshot_path)) {
|
||||
file_put_contents('php://stderr', sprintf('"%s" directory is not writable' . PHP_EOL, $screenshot_path));
|
||||
if (file_exists($path) && !is_writable($path)) {
|
||||
file_put_contents('php://stderr', sprintf('"%s" directory is not writable' . PHP_EOL, $path));
|
||||
return;
|
||||
}
|
||||
|
||||
$screenshot_path = sprintf('%s/%s_%d.png', $screenshot_path, basename($feature->getFile()), $step->getLine());
|
||||
$path = sprintf('%s/%s_%d.png', $path, basename($feature->getFile()), $step->getLine());
|
||||
$screenshot = $driver->wdSession->screenshot();
|
||||
file_put_contents($screenshot_path, base64_decode($screenshot));
|
||||
file_put_contents('php://stderr', sprintf('Saving screenshot into %s' . PHP_EOL, $screenshot_path));
|
||||
file_put_contents($path, base64_decode($screenshot));
|
||||
file_put_contents('php://stderr', sprintf('Saving screenshot into %s' . PHP_EOL, $path));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,17 +24,41 @@ use SilverStripe\BehatExtension\Context\SilverStripeAwareContextInterface;
|
||||
*/
|
||||
class SilverStripeAwareInitializer implements InitializerInterface
|
||||
{
|
||||
|
||||
private $database_name;
|
||||
private $ajax_steps;
|
||||
|
||||
/**
|
||||
* @var Array
|
||||
*/
|
||||
protected $ajaxSteps;
|
||||
|
||||
/**
|
||||
* @var Int Timeout in milliseconds
|
||||
*/
|
||||
protected $ajaxTimeout;
|
||||
|
||||
/**
|
||||
* @var String {@link see SilverStripeContext}
|
||||
*/
|
||||
protected $adminUrl;
|
||||
|
||||
/**
|
||||
* @var String {@link see SilverStripeContext}
|
||||
*/
|
||||
protected $loginUrl;
|
||||
|
||||
/**
|
||||
* @var String {@link see SilverStripeContext}
|
||||
*/
|
||||
protected $screenshotPath;
|
||||
|
||||
/**
|
||||
* Initializes initializer.
|
||||
*/
|
||||
public function __construct($framework_path, $framework_host, $ajax_steps)
|
||||
public function __construct($framework_path, $framework_host)
|
||||
{
|
||||
$this->bootstrap($framework_path, $framework_host);
|
||||
$this->database_name = $this->initializeTempDb();
|
||||
$this->ajax_steps = $ajax_steps;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
@ -62,7 +86,61 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
public function initialize(ContextInterface $context)
|
||||
{
|
||||
$context->setDatabase($this->database_name);
|
||||
$context->setAjaxEnabledSteps($this->ajax_steps);
|
||||
$context->setAjaxSteps($this->ajaxSteps);
|
||||
$context->setAjaxTimeout($this->ajaxTimeout);
|
||||
$context->setScreenshotPath($this->screenshotPath);
|
||||
$context->setAdminUrl($this->adminUrl);
|
||||
$context->setLoginUrl($this->loginUrl);
|
||||
}
|
||||
|
||||
public function setAjaxSteps($ajaxSteps)
|
||||
{
|
||||
if($ajaxSteps) $this->ajaxSteps = $ajaxSteps;
|
||||
}
|
||||
|
||||
public function getAjaxSteps()
|
||||
{
|
||||
return $this->ajaxSteps;
|
||||
}
|
||||
|
||||
public function setAjaxTimeout($ajaxTimeout)
|
||||
{
|
||||
$this->ajaxTimeout = $ajaxTimeout;
|
||||
}
|
||||
|
||||
public function getAjaxTimeout()
|
||||
{
|
||||
return $this->ajaxTimeout;
|
||||
}
|
||||
|
||||
public function setAdminUrl($adminUrl)
|
||||
{
|
||||
$this->adminUrl = $adminUrl;
|
||||
}
|
||||
|
||||
public function getAdminUrl()
|
||||
{
|
||||
return $this->adminUrl;
|
||||
}
|
||||
|
||||
public function setLoginUrl($loginUrl)
|
||||
{
|
||||
$this->loginUrl = $loginUrl;
|
||||
}
|
||||
|
||||
public function getLoginUrl()
|
||||
{
|
||||
return $this->loginUrl;
|
||||
}
|
||||
|
||||
public function setScreenshotPath($screenshotPath)
|
||||
{
|
||||
$this->screenshotPath = $screenshotPath;
|
||||
}
|
||||
|
||||
public function getScreenshotPath()
|
||||
{
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
|
||||
protected function bootstrap($framework_path, $framework_host)
|
||||
|
@ -53,8 +53,9 @@ class LoginContext extends BehatContext
|
||||
*/
|
||||
public function stepIAmLoggedIn()
|
||||
{
|
||||
$admin_url = $this->getMainContext()->joinUrlParts($this->getMainContext()->getBaseUrl(), $this->context['admin_url']);
|
||||
$login_url = $this->getMainContext()->joinUrlParts($this->getMainContext()->getBaseUrl(), $this->context['login_url']);
|
||||
$c = $this->getMainContext();
|
||||
$admin_url = $c->joinUrlParts($c->getBaseUrl(), $c->getAdminUrl());
|
||||
$login_url = $c->joinUrlParts($c->getBaseUrl(), $c->getLoginUrl());
|
||||
|
||||
$this->getSession()->visit($admin_url);
|
||||
|
||||
@ -111,7 +112,8 @@ class LoginContext extends BehatContext
|
||||
*/
|
||||
public function stepILogInWith($email, $password)
|
||||
{
|
||||
$login_url = $this->getMainContext()->joinUrlParts($this->getMainContext()->getBaseUrl(), $this->context['login_url']);
|
||||
$c = $this->getMainContext();
|
||||
$login_url = $c->joinUrlParts($c->getBaseUrl(), $c->getLoginUrl());
|
||||
|
||||
$this->getSession()->visit($login_url);
|
||||
|
||||
|
@ -30,5 +30,5 @@ interface SilverStripeAwareContextInterface
|
||||
*
|
||||
* @param array $ajax_steps Array of step name parts to match
|
||||
*/
|
||||
public function setAjaxEnabledSteps($ajax_steps);
|
||||
public function setAjaxSteps($ajax_steps);
|
||||
}
|
||||
|
@ -26,8 +26,37 @@ require_once 'vendor/autoload.php';
|
||||
*/
|
||||
class SilverStripeContext extends MinkContext implements SilverStripeAwareContextInterface
|
||||
{
|
||||
private $database_name;
|
||||
private $ajax_steps;
|
||||
protected $database_name;
|
||||
|
||||
/**
|
||||
* @var Array Partial string match for step names
|
||||
* that are considered to trigger Ajax request in the CMS,
|
||||
* and hence need special timeout handling.
|
||||
* @see \SilverStripe\BehatExtension\Context\BasicContext->handleAjaxBeforeStep().
|
||||
*/
|
||||
protected $ajaxSteps;
|
||||
|
||||
/**
|
||||
* @var Int Timeout in milliseconds, after which the interface assumes
|
||||
* that an Ajax request has timed out, and continues with assertions.
|
||||
*/
|
||||
protected $ajaxTimeout;
|
||||
|
||||
/**
|
||||
* @var String Relative URL to the SilverStripe admin interface.
|
||||
*/
|
||||
protected $adminUrl;
|
||||
|
||||
/**
|
||||
* @var String Relative URL to the SilverStripe login form.
|
||||
*/
|
||||
protected $loginUrl;
|
||||
|
||||
/**
|
||||
* @var String Relative path to a writeable folder where screenshots can be stored.
|
||||
* If set to NULL, no screenshots will be stored.
|
||||
*/
|
||||
protected $screenshotPath;
|
||||
|
||||
protected $context;
|
||||
protected $fixtures;
|
||||
@ -52,17 +81,54 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||
$this->database_name = $database_name;
|
||||
}
|
||||
|
||||
public function setAjaxEnabledSteps($ajax_steps)
|
||||
public function setAjaxSteps($ajaxSteps)
|
||||
{
|
||||
if (empty($ajax_steps)) {
|
||||
$ajax_steps = array();
|
||||
}
|
||||
$this->ajax_steps = $ajax_steps;
|
||||
if($ajaxSteps) $this->ajaxSteps = $ajaxSteps;
|
||||
}
|
||||
|
||||
public function getAjaxEnabledSteps()
|
||||
public function getAjaxSteps()
|
||||
{
|
||||
return $this->ajax_steps;
|
||||
return $this->ajaxSteps;
|
||||
}
|
||||
|
||||
public function setAjaxTimeout($ajaxTimeout)
|
||||
{
|
||||
$this->ajaxTimeout = $ajaxTimeout;
|
||||
}
|
||||
|
||||
public function getAjaxTimeout()
|
||||
{
|
||||
return $this->ajaxTimeout;
|
||||
}
|
||||
|
||||
public function setAdminUrl($adminUrl)
|
||||
{
|
||||
$this->adminUrl = $adminUrl;
|
||||
}
|
||||
|
||||
public function getAdminUrl()
|
||||
{
|
||||
return $this->adminUrl;
|
||||
}
|
||||
|
||||
public function setLoginUrl($loginUrl)
|
||||
{
|
||||
$this->loginUrl = $loginUrl;
|
||||
}
|
||||
|
||||
public function getLoginUrl()
|
||||
{
|
||||
return $this->loginUrl;
|
||||
}
|
||||
|
||||
public function setScreenshotPath($screenshotPath)
|
||||
{
|
||||
$this->screenshotPath = $screenshotPath;
|
||||
}
|
||||
|
||||
public function getScreenshotPath()
|
||||
{
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
|
||||
public function getFixture($data_object)
|
||||
|
@ -4,9 +4,10 @@ namespace SilverStripe\BehatExtension;
|
||||
|
||||
use Symfony\Component\Config\FileLocator,
|
||||
Symfony\Component\DependencyInjection\ContainerBuilder,
|
||||
Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
Symfony\Component\DependencyInjection\Loader\YamlFileLoader,
|
||||
Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
|
||||
use Behat\Behat\Extension\Extension as BaseExtension;
|
||||
use Behat\Behat\Extension\ExtensionInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the SilverStripe\BehatExtension
|
||||
@ -22,7 +23,7 @@ use Behat\Behat\Extension\Extension as BaseExtension;
|
||||
*
|
||||
* @author Michał Ochman <ochman.d.michal@gmail.com>
|
||||
*/
|
||||
class Extension extends BaseExtension
|
||||
class Extension implements ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* Loads a specific configuration.
|
||||
@ -50,6 +51,10 @@ class Extension extends BaseExtension
|
||||
}
|
||||
|
||||
$container->setParameter('behat.silverstripe_extension.framework_path', $config['framework_path']);
|
||||
$container->setParameter('behat.silverstripe_extension.admin_url', $config['admin_url']);
|
||||
$container->setParameter('behat.silverstripe_extension.login_url', $config['login_url']);
|
||||
$container->setParameter('behat.silverstripe_extension.screenshot_path', $config['screenshot_path']);
|
||||
$container->setParameter('behat.silverstripe_extension.ajax_timeout', $config['ajax_timeout']);
|
||||
if (isset($config['ajax_steps'])) {
|
||||
$container->setParameter('behat.silverstripe_extension.ajax_steps', $config['ajax_steps']);
|
||||
}
|
||||
@ -66,4 +71,42 @@ class Extension extends BaseExtension
|
||||
new Compiler\MinkExtensionBaseUrlPass(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups configuration for current extension.
|
||||
*
|
||||
* @param ArrayNodeDefinition $builder
|
||||
*/
|
||||
function getConfig(ArrayNodeDefinition $builder)
|
||||
{
|
||||
$builder->
|
||||
children()->
|
||||
scalarNode('framework_path')->
|
||||
defaultValue('../../../framework')->
|
||||
end()->
|
||||
scalarNode('screenshot_path')->
|
||||
defaultNull()->
|
||||
end()->
|
||||
scalarNode('admin_url')->
|
||||
defaultValue('/admin/')->
|
||||
end()->
|
||||
scalarNode('login_url')->
|
||||
defaultValue('/Security/login')->
|
||||
end()->
|
||||
scalarNode('ajax_timeout')->
|
||||
defaultValue(5000)->
|
||||
end()->
|
||||
arrayNode('ajax_steps')->
|
||||
defaultValue(array(
|
||||
'go to',
|
||||
'follow',
|
||||
'press',
|
||||
'click',
|
||||
'submit'
|
||||
))->
|
||||
prototype('scalar')->
|
||||
end()->
|
||||
end()->
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,21 @@ parameters:
|
||||
behat.silverstripe_extension.context.initializer.class: SilverStripe\BehatExtension\Context\Initializer\SilverStripeAwareInitializer
|
||||
behat.silverstripe_extension.framework_path: ~
|
||||
behat.silverstripe_extension.ajax_steps: ~
|
||||
behat.silverstripe_extension.ajax_timeout: ~
|
||||
behat.silverstripe_extension.admin_url: ~
|
||||
behat.silverstripe_extension.login_url: ~
|
||||
behat.silverstripe_extension.screenshot_path: ~
|
||||
services:
|
||||
behat.silverstripe_extension.context.initializer:
|
||||
class: %behat.silverstripe_extension.context.initializer.class%
|
||||
arguments:
|
||||
- %behat.silverstripe_extension.framework_path%
|
||||
- %behat.silverstripe_extension.framework_host%
|
||||
- %behat.silverstripe_extension.ajax_steps%
|
||||
calls:
|
||||
- [setAjaxSteps, [%behat.silverstripe_extension.ajax_steps%]]
|
||||
- [setAjaxTimeout, [%behat.silverstripe_extension.ajax_timeout%]]
|
||||
- [setAdminUrl, [%behat.silverstripe_extension.admin_url%]]
|
||||
- [setLoginUrl, [%behat.silverstripe_extension.login_url%]]
|
||||
- [setScreenshotPath, [%behat.silverstripe_extension.screenshot_path%]]
|
||||
tags:
|
||||
- { name: behat.context.initializer }
|
||||
|
Loading…
Reference in New Issue
Block a user