mirror of
https://github.com/silverstripe/silverstripe-behat-extension
synced 2024-10-22 17:05:32 +02:00
Merge pull request #123 from open-sausages/pulls/4.0/psr2
Convert to PSR-2 standard
This commit is contained in:
commit
ce3c0bb6c7
23
.travis.yml
23
.travis.yml
@ -3,11 +3,24 @@ language: php
|
||||
sudo: false
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit tests
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- PHPUNIT_TEST=1
|
||||
- PHPCS_TEST=1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.5
|
||||
env: PHPUNIT_TEST=1
|
||||
|
||||
before_script:
|
||||
- composer install --dev --prefer-dist
|
||||
- composer install --dev --prefer-dist
|
||||
- pyrus install pear/PHP_CodeSniffer
|
||||
- phpenv rehash
|
||||
|
||||
|
||||
script:
|
||||
- "if [ \"$PHPUNIT_TEST\" = \"1\" ]; then vendor/bin/phpunit tests; fi"
|
||||
- "if [ \"$PHPCS_TEST\" = \"1\" ]; then phpcs --standard=PSR2 -n src/ tests/; fi"
|
||||
|
5
init.php
5
init.php
@ -9,12 +9,11 @@
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
spl_autoload_register(function($class)
|
||||
{
|
||||
spl_autoload_register(function ($class) {
|
||||
if (false !== strpos($class, 'SilverStripe\\BehatExtension')) {
|
||||
require_once(__DIR__ . '/src/' . str_replace('\\', '/', $class) . '.php');
|
||||
return true;
|
||||
}
|
||||
}, true, false);
|
||||
|
||||
return new SilverStripe\BehatExtension\Extension;
|
||||
return new SilverStripe\BehatExtension\Extension;
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder,
|
||||
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
/**
|
||||
* Loads SilverStripe core. Required to initialize autoloading.
|
||||
@ -22,7 +22,7 @@ class CoreInitializationPass implements CompilerPassInterface
|
||||
$_GET['flush'] = 1;
|
||||
require_once $frameworkPath . '/core/Core.php';
|
||||
|
||||
if(class_exists('TestRunner')) {
|
||||
if (class_exists('TestRunner')) {
|
||||
// 3.x compat
|
||||
\TestRunner::use_test_manifest();
|
||||
} else {
|
||||
@ -34,4 +34,4 @@ class CoreInitializationPass implements CompilerPassInterface
|
||||
// Remove the error handler so that PHPUnit can add its own
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder,
|
||||
Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
/**
|
||||
* Behat\SilverStripe container compilation pass.
|
||||
@ -24,22 +24,23 @@ class MinkExtensionBaseUrlPass implements CompilerPassInterface
|
||||
$frameworkPath = $container->getParameter('behat.silverstripe_extension.framework_path');
|
||||
|
||||
global $_FILE_TO_URL_MAPPING;
|
||||
if($container->getParameter('behat.mink.base_url')) {
|
||||
if ($container->getParameter('behat.mink.base_url')) {
|
||||
// If base_url is already defined, also set it in the SilverStripe mapping
|
||||
$_FILE_TO_URL_MAPPING[dirname($frameworkPath)] = $container->getParameter('behat.mink.base_url');
|
||||
} else if($envPath = $this->findEnvironmentConfigFile($frameworkPath)) {
|
||||
} elseif ($envPath = $this->findEnvironmentConfigFile($frameworkPath)) {
|
||||
// Otherwise try to retrieve it from _ss_environment
|
||||
include_once $envPath;
|
||||
if(
|
||||
isset($_FILE_TO_URL_MAPPING)
|
||||
if (isset($_FILE_TO_URL_MAPPING)
|
||||
&& !($container->hasParameter('behat.mink.base_url') && $container->getParameter('behat.mink.base_url'))
|
||||
) {
|
||||
$baseUrl = $this->findBaseUrlFromMapping(dirname($frameworkPath), $_FILE_TO_URL_MAPPING);
|
||||
if($baseUrl) $container->setParameter('behat.mink.base_url', $baseUrl);
|
||||
if ($baseUrl) {
|
||||
$container->setParameter('behat.mink.base_url', $baseUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!$container->getParameter('behat.mink.base_url')) {
|
||||
if (!$container->getParameter('behat.mink.base_url')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'"base_url" not configured. Please specify it in your behat.yml configuration, ' .
|
||||
'or in your _ss_environment.php configuration through $_FILE_TO_URL_MAPPING'
|
||||
@ -60,11 +61,12 @@ class MinkExtensionBaseUrlPass implements CompilerPassInterface
|
||||
* @param String Absolute start path to search upwards from
|
||||
* @return Boolean Absolute path to environment file
|
||||
*/
|
||||
protected function findEnvironmentConfigFile($path) {
|
||||
protected function findEnvironmentConfigFile($path)
|
||||
{
|
||||
$envPath = null;
|
||||
$envFile = '_ss_environment.php'; //define the name of the environment file
|
||||
$path = '.'; //define the dir to start scanning from (have to add the trailing slash)
|
||||
|
||||
|
||||
//check this dir and every parent dir (until we hit the base of the drive)
|
||||
do {
|
||||
$path = realpath($path) . '/';
|
||||
@ -87,12 +89,13 @@ class MinkExtensionBaseUrlPass implements CompilerPassInterface
|
||||
* @param Array Map of paths to host names
|
||||
* @return String URL
|
||||
*/
|
||||
protected function findBaseUrlFromMapping($path, $mapping) {
|
||||
protected function findBaseUrlFromMapping($path, $mapping)
|
||||
{
|
||||
$fullPath = $path;
|
||||
$url = null;
|
||||
while($path && $path != "/" && !preg_match('/^[A-Z]:\\\\$/', $path)) {
|
||||
if(isset($mapping[$path])) {
|
||||
$url = $mapping[$path] . str_replace(DIRECTORY_SEPARATOR, '/', substr($fullPath,strlen($path)));
|
||||
while ($path && $path != "/" && !preg_match('/^[A-Z]:\\\\$/', $path)) {
|
||||
if (isset($mapping[$path])) {
|
||||
$url = $mapping[$path] . str_replace(DIRECTORY_SEPARATOR, '/', substr($fullPath, strlen($path)));
|
||||
break;
|
||||
} else {
|
||||
$path = dirname($path); // traverse up
|
||||
|
@ -2,12 +2,12 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Console\Processor;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface,
|
||||
Symfony\Component\Console\Command\Command,
|
||||
Symfony\Component\Console\Input\InputArgument,
|
||||
Symfony\Component\Console\Input\InputInterface,
|
||||
Symfony\Component\Console\Output\OutputInterface,
|
||||
Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use Behat\Behat\Console\Processor\InitProcessor as BaseProcessor;
|
||||
|
||||
@ -33,7 +33,10 @@ class InitProcessor extends BaseProcessor
|
||||
{
|
||||
parent::configure($command);
|
||||
|
||||
$command->addOption('--namespace', null, InputOption::VALUE_OPTIONAL,
|
||||
$command->addOption(
|
||||
'--namespace',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"Optional namespace for FeatureContext, defaults to <foldername>\\Test\\Behaviour.\n"
|
||||
);
|
||||
}
|
||||
@ -68,7 +71,7 @@ class InitProcessor extends BaseProcessor
|
||||
unset($_GET['flush']);
|
||||
|
||||
$featuresPath = $input->getArgument('features');
|
||||
if(!$featuresPath) {
|
||||
if (!$featuresPath) {
|
||||
throw new \InvalidArgumentException('Please specify a module name (e.g. "@mymodule")');
|
||||
}
|
||||
|
||||
@ -86,21 +89,21 @@ class InitProcessor extends BaseProcessor
|
||||
throw new \InvalidArgumentException(sprintf('Module "%s" not found', $currentModuleName));
|
||||
}
|
||||
$currentModulePath = $modules[$currentModuleName];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$currentModuleName) {
|
||||
throw new \InvalidArgumentException('Can not find module to initialize suite.');
|
||||
}
|
||||
|
||||
// TODO Retrieve from module definition once that's implemented
|
||||
if($input->getOption('namespace')) {
|
||||
if ($input->getOption('namespace')) {
|
||||
$namespace = $input->getOption('namespace');
|
||||
} else {
|
||||
$namespace = ucfirst($currentModuleName);
|
||||
}
|
||||
$namespace .= '\\' . $this->container->getParameter('behat.silverstripe_extension.context.namespace_suffix');
|
||||
|
||||
$featuresPath = rtrim($currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix,DIRECTORY_SEPARATOR);
|
||||
$featuresPath = rtrim($currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix, DIRECTORY_SEPARATOR);
|
||||
$basePath = $this->container->getParameter('behat.paths.base').DIRECTORY_SEPARATOR;
|
||||
$bootstrapPath = $featuresPath.DIRECTORY_SEPARATOR.'bootstrap';
|
||||
$contextPath = $bootstrapPath.DIRECTORY_SEPARATOR.'Context';
|
||||
@ -140,7 +143,7 @@ class InitProcessor extends BaseProcessor
|
||||
*/
|
||||
protected function getFeatureContextSkelet()
|
||||
{
|
||||
return <<<'PHP'
|
||||
return <<<'PHP'
|
||||
<?php
|
||||
|
||||
namespace %NAMESPACE%;
|
||||
@ -242,4 +245,4 @@ class FeatureContext extends SilverStripeContext {
|
||||
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Console\Processor;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface,
|
||||
Symfony\Component\Console\Command\Command,
|
||||
Symfony\Component\Console\Input\InputArgument,
|
||||
Symfony\Component\Console\Input\InputInterface,
|
||||
Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use Behat\Behat\Console\Processor\LocatorProcessor as BaseProcessor;
|
||||
|
||||
@ -34,7 +34,9 @@ class LocatorProcessor extends BaseProcessor
|
||||
*/
|
||||
public function configure(Command $command)
|
||||
{
|
||||
$command->addArgument('features', InputArgument::OPTIONAL,
|
||||
$command->addArgument(
|
||||
'features',
|
||||
InputArgument::OPTIONAL,
|
||||
"Feature(s) to run. Could be:".
|
||||
"\n- a dir (<comment>src/to/module/Features/</comment>), " .
|
||||
"\n- a feature (<comment>src/to/module/Features/*.feature</comment>), " .
|
||||
@ -91,7 +93,7 @@ class LocatorProcessor extends BaseProcessor
|
||||
$featuresPath = $currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix.DIRECTORY_SEPARATOR.$featuresPath;
|
||||
}
|
||||
|
||||
if($input->getOption('namespace')) {
|
||||
if ($input->getOption('namespace')) {
|
||||
$namespace = $input->getOption('namespace');
|
||||
} else {
|
||||
$namespace = ucfirst($currentModuleName);
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Context;
|
||||
|
||||
use Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Event\StepEvent,
|
||||
Behat\Behat\Event\ScenarioEvent;
|
||||
use Behat\Behat\Context\BehatContext;
|
||||
use Behat\Behat\Context\Step;
|
||||
use Behat\Behat\Event\StepEvent;
|
||||
use Behat\Behat\Event\ScenarioEvent;
|
||||
|
||||
use Behat\Mink\Driver\Selenium2Driver;
|
||||
|
||||
use Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
use Behat\Gherkin\Node\PyStringNode;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
|
||||
// PHPUnit
|
||||
require_once BASE_PATH . '/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php';
|
||||
@ -28,22 +28,22 @@ class BasicContext extends BehatContext
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* Date format in date() syntax
|
||||
* @var String
|
||||
*/
|
||||
protected $dateFormat = 'Y-m-d';
|
||||
* Date format in date() syntax
|
||||
* @var String
|
||||
*/
|
||||
protected $dateFormat = 'Y-m-d';
|
||||
|
||||
/**
|
||||
* Time format in date() syntax
|
||||
* @var String
|
||||
*/
|
||||
protected $timeFormat = 'H:i:s';
|
||||
/**
|
||||
* Time format in date() syntax
|
||||
* @var String
|
||||
*/
|
||||
protected $timeFormat = 'H:i:s';
|
||||
|
||||
/**
|
||||
* Date/time format in date() syntax
|
||||
* @var String
|
||||
*/
|
||||
protected $datetimeFormat = 'Y-m-d H:i:s';
|
||||
/**
|
||||
* Date/time format in date() syntax
|
||||
* @var String
|
||||
*/
|
||||
protected $datetimeFormat = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* Initializes context.
|
||||
@ -51,19 +51,21 @@ class BasicContext extends BehatContext
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters) {
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Mink session from MinkContext
|
||||
*
|
||||
* @return \Behat\Mink\Session
|
||||
*/
|
||||
public function getSession($name = null) {
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
/**
|
||||
* Get Mink session from MinkContext
|
||||
*
|
||||
* @return \Behat\Mink\Session
|
||||
*/
|
||||
public function getSession($name = null)
|
||||
{
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterStep ~@modal
|
||||
@ -71,9 +73,10 @@ class BasicContext extends BehatContext
|
||||
* Excluding scenarios with @modal tag is required,
|
||||
* because modal dialogs stop any JS interaction
|
||||
*/
|
||||
public function appendErrorHandlerBeforeStep(StepEvent $event) {
|
||||
try{
|
||||
$javascript = <<<JS
|
||||
public function appendErrorHandlerBeforeStep(StepEvent $event)
|
||||
{
|
||||
try {
|
||||
$javascript = <<<JS
|
||||
window.onerror = function(message, file, line, column, error) {
|
||||
var body = document.getElementsByTagName('body')[0];
|
||||
var msg = message + " in " + file + ":" + line + ":" + column;
|
||||
@ -90,9 +93,9 @@ if ('undefined' !== typeof window.jQuery) {
|
||||
}
|
||||
JS;
|
||||
|
||||
$this->getSession()->executeScript($javascript);
|
||||
}catch(\WebDriver\Exception $e){
|
||||
$this->logException($e);
|
||||
$this->getSession()->executeScript($javascript);
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,17 +105,18 @@ JS;
|
||||
* Excluding scenarios with @modal tag is required,
|
||||
* because modal dialogs stop any JS interaction
|
||||
*/
|
||||
public function readErrorHandlerAfterStep(StepEvent $event) {
|
||||
try{
|
||||
$page = $this->getSession()->getPage();
|
||||
public function readErrorHandlerAfterStep(StepEvent $event)
|
||||
{
|
||||
try {
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$jserrors = $page->find('xpath', '//body[@data-jserrors]');
|
||||
if (null !== $jserrors) {
|
||||
$this->takeScreenshot($event);
|
||||
file_put_contents('php://stderr', $jserrors->getAttribute('data-jserrors') . PHP_EOL);
|
||||
}
|
||||
$jserrors = $page->find('xpath', '//body[@data-jserrors]');
|
||||
if (null !== $jserrors) {
|
||||
$this->takeScreenshot($event);
|
||||
file_put_contents('php://stderr', $jserrors->getAttribute('data-jserrors') . PHP_EOL);
|
||||
}
|
||||
|
||||
$javascript = <<<JS
|
||||
$javascript = <<<JS
|
||||
if ('undefined' !== typeof window.jQuery) {
|
||||
window.jQuery(document).ready(function() {
|
||||
window.jQuery('body').removeAttr('data-jserrors');
|
||||
@ -120,9 +124,9 @@ if ('undefined' !== typeof window.jQuery) {
|
||||
}
|
||||
JS;
|
||||
|
||||
$this->getSession()->executeScript($javascript);
|
||||
}catch(\WebDriver\Exception $e){
|
||||
$this->logException($e);
|
||||
$this->getSession()->executeScript($javascript);
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,16 +137,17 @@ JS;
|
||||
*
|
||||
* @BeforeStep
|
||||
*/
|
||||
public function handleAjaxBeforeStep(StepEvent $event) {
|
||||
try{
|
||||
$ajaxEnabledSteps = $this->getMainContext()->getAjaxSteps();
|
||||
$ajaxEnabledSteps = implode('|', array_filter($ajaxEnabledSteps));
|
||||
public function handleAjaxBeforeStep(StepEvent $event)
|
||||
{
|
||||
try {
|
||||
$ajaxEnabledSteps = $this->getMainContext()->getAjaxSteps();
|
||||
$ajaxEnabledSteps = implode('|', array_filter($ajaxEnabledSteps));
|
||||
|
||||
if (empty($ajaxEnabledSteps) || !preg_match('/(' . $ajaxEnabledSteps . ')/i', $event->getStep()->getText())) {
|
||||
return;
|
||||
}
|
||||
if (empty($ajaxEnabledSteps) || !preg_match('/(' . $ajaxEnabledSteps . ')/i', $event->getStep()->getText())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$javascript = <<<JS
|
||||
$javascript = <<<JS
|
||||
if ('undefined' !== typeof window.jQuery && 'undefined' !== typeof window.jQuery.fn.on) {
|
||||
window.jQuery(document).on('ajaxStart.ss.test.behaviour', function(){
|
||||
window.__ajaxStatus = function() {
|
||||
@ -165,10 +170,10 @@ if ('undefined' !== typeof window.jQuery && 'undefined' !== typeof window.jQuery
|
||||
});
|
||||
}
|
||||
JS;
|
||||
$this->getSession()->wait(500); // give browser a chance to process and render response
|
||||
$this->getSession()->executeScript($javascript);
|
||||
}catch(\WebDriver\Exception $e){
|
||||
$this->logException($e);
|
||||
$this->getSession()->wait(500); // give browser a chance to process and render response
|
||||
$this->getSession()->executeScript($javascript);
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,35 +185,38 @@ JS;
|
||||
*
|
||||
* @AfterStep ~@modal
|
||||
*/
|
||||
public function handleAjaxAfterStep(StepEvent $event) {
|
||||
try{
|
||||
$ajaxEnabledSteps = $this->getMainContext()->getAjaxSteps();
|
||||
$ajaxEnabledSteps = implode('|', array_filter($ajaxEnabledSteps));
|
||||
public function handleAjaxAfterStep(StepEvent $event)
|
||||
{
|
||||
try {
|
||||
$ajaxEnabledSteps = $this->getMainContext()->getAjaxSteps();
|
||||
$ajaxEnabledSteps = implode('|', array_filter($ajaxEnabledSteps));
|
||||
|
||||
if (empty($ajaxEnabledSteps) || !preg_match('/(' . $ajaxEnabledSteps . ')/i', $event->getStep()->getText())) {
|
||||
return;
|
||||
}
|
||||
if (empty($ajaxEnabledSteps) || !preg_match('/(' . $ajaxEnabledSteps . ')/i', $event->getStep()->getText())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->handleAjaxTimeout();
|
||||
$this->handleAjaxTimeout();
|
||||
|
||||
$javascript = <<<JS
|
||||
$javascript = <<<JS
|
||||
if ('undefined' !== typeof window.jQuery && 'undefined' !== typeof window.jQuery.fn.off) {
|
||||
window.jQuery(document).off('ajaxStart.ss.test.behaviour');
|
||||
window.jQuery(document).off('ajaxComplete.ss.test.behaviour');
|
||||
window.jQuery(document).off('ajaxSuccess.ss.test.behaviour');
|
||||
}
|
||||
JS;
|
||||
$this->getSession()->executeScript($javascript);
|
||||
}catch(\WebDriver\Exception $e){
|
||||
$this->logException($e);
|
||||
$this->getSession()->executeScript($javascript);
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function handleAjaxTimeout() {
|
||||
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($timeoutMs,
|
||||
$this->getSession()->wait(
|
||||
$timeoutMs,
|
||||
"(typeof window.__ajaxStatus !== 'undefined' ? window.__ajaxStatus() : 'no ajax') !== 'waiting'"
|
||||
);
|
||||
|
||||
@ -222,54 +230,58 @@ JS;
|
||||
*
|
||||
* @AfterStep
|
||||
*/
|
||||
public function takeScreenshotAfterFailedStep(StepEvent $event) {
|
||||
if (4 === $event->getResult()) {
|
||||
try{
|
||||
$this->takeScreenshot($event);
|
||||
}catch(\WebDriver\Exception $e){
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function takeScreenshotAfterFailedStep(StepEvent $event)
|
||||
{
|
||||
if (4 === $event->getResult()) {
|
||||
try {
|
||||
$this->takeScreenshot($event);
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close modal dialog if test scenario fails on CMS page
|
||||
*
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function closeModalDialog(ScenarioEvent $event) {
|
||||
try{
|
||||
// Only for failed tests on CMS page
|
||||
if (4 === $event->getResult()) {
|
||||
$cmsElement = $this->getSession()->getPage()->find('css', '.cms');
|
||||
if($cmsElement) {
|
||||
try {
|
||||
// Navigate away triggered by reloading the page
|
||||
$this->getSession()->reload();
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
|
||||
} catch(\WebDriver\Exception $e) {
|
||||
// no-op, alert might not be present
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch(\WebDriver\Exception $e){
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Close modal dialog if test scenario fails on CMS page
|
||||
*
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function closeModalDialog(ScenarioEvent $event)
|
||||
{
|
||||
try {
|
||||
// Only for failed tests on CMS page
|
||||
if (4 === $event->getResult()) {
|
||||
$cmsElement = $this->getSession()->getPage()->find('css', '.cms');
|
||||
if ($cmsElement) {
|
||||
try {
|
||||
// Navigate away triggered by reloading the page
|
||||
$this->getSession()->reload();
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
// no-op, alert might not be present
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\WebDriver\Exception $e) {
|
||||
$this->logException($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete any created files and folders from assets directory
|
||||
*
|
||||
* @AfterScenario @assets
|
||||
*/
|
||||
public function cleanAssetsAfterScenario(ScenarioEvent $event) {
|
||||
foreach(\File::get() as $file) {
|
||||
public function cleanAssetsAfterScenario(ScenarioEvent $event)
|
||||
{
|
||||
foreach (\File::get() as $file) {
|
||||
$file->delete();
|
||||
}
|
||||
\Filesystem::removeFolder(ASSETS_PATH, true);
|
||||
\Filesystem::removeFolder(ASSETS_PATH, true);
|
||||
}
|
||||
|
||||
public function takeScreenshot(StepEvent $event) {
|
||||
public function takeScreenshot(StepEvent $event)
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
// quit silently when unsupported
|
||||
if (!($driver instanceof Selenium2Driver)) {
|
||||
@ -282,7 +294,9 @@ JS;
|
||||
$screenshotPath = null;
|
||||
|
||||
$path = $this->getMainContext()->getScreenshotPath();
|
||||
if(!$path) return; // quit silently when path is not set
|
||||
if (!$path) {
|
||||
return;
|
||||
} // quit silently when path is not set
|
||||
|
||||
\Filesystem::makeFolder($path);
|
||||
$path = realpath($path);
|
||||
@ -310,7 +324,8 @@ JS;
|
||||
/**
|
||||
* @Then /^I should be redirected to "([^"]+)"/
|
||||
*/
|
||||
public function stepIShouldBeRedirectedTo($url) {
|
||||
public function stepIShouldBeRedirectedTo($url)
|
||||
{
|
||||
if ($this->getMainContext()->canIntercept()) {
|
||||
$client = $this->getSession()->getDriver()->getClient();
|
||||
$client->followRedirects(true);
|
||||
@ -325,7 +340,8 @@ JS;
|
||||
/**
|
||||
* @Given /^the page can't be found/
|
||||
*/
|
||||
public function stepPageCantBeFound() {
|
||||
public function stepPageCantBeFound()
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
assertTrue(
|
||||
// Content from ErrorPage default record
|
||||
@ -338,19 +354,23 @@ JS;
|
||||
/**
|
||||
* @Given /^I wait (?:for )?([\d\.]+) second(?:s?)$/
|
||||
*/
|
||||
public function stepIWaitFor($secs) {
|
||||
public function stepIWaitFor($secs)
|
||||
{
|
||||
$this->getSession()->wait((float)$secs*1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I press the "([^"]*)" button$/
|
||||
*/
|
||||
public function stepIPressTheButton($button) {
|
||||
public function stepIPressTheButton($button)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$els = $page->findAll('named', array('link_or_button', "'$button'"));
|
||||
$matchedEl = null;
|
||||
foreach($els as $el) {
|
||||
if($el->isVisible()) $matchedEl = $el;
|
||||
foreach ($els as $el) {
|
||||
if ($el->isVisible()) {
|
||||
$matchedEl = $el;
|
||||
}
|
||||
}
|
||||
assertNotNull($matchedEl, sprintf('%s button not found', $button));
|
||||
$matchedEl->click();
|
||||
@ -363,7 +383,8 @@ JS;
|
||||
*
|
||||
* @Given /^I (?:press|follow) the "([^"]*)" (?:button|link), confirming the dialog$/
|
||||
*/
|
||||
public function stepIPressTheButtonConfirmingTheDialog($button) {
|
||||
public function stepIPressTheButtonConfirmingTheDialog($button)
|
||||
{
|
||||
$this->stepIPressTheButton($button);
|
||||
$this->iConfirmTheDialog();
|
||||
}
|
||||
@ -374,15 +395,17 @@ JS;
|
||||
*
|
||||
* @Given /^I (?:press|follow) the "([^"]*)" (?:button|link), dismissing the dialog$/
|
||||
*/
|
||||
public function stepIPressTheButtonDismissingTheDialog($button) {
|
||||
$this->stepIPressTheButton($button);
|
||||
$this->iDismissTheDialog();
|
||||
public function stepIPressTheButtonDismissingTheDialog($button)
|
||||
{
|
||||
$this->stepIPressTheButton($button);
|
||||
$this->iDismissTheDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I (click|double click) "([^"]*)" in the "([^"]*)" element$/
|
||||
*/
|
||||
public function iClickInTheElement($clickType, $text, $selector) {
|
||||
public function iClickInTheElement($clickType, $text, $selector)
|
||||
{
|
||||
$clickTypeMap = array(
|
||||
"double click" => "doubleclick",
|
||||
"click" => "click"
|
||||
@ -402,25 +425,28 @@ JS;
|
||||
*
|
||||
* @Given /^I (click|double click) "([^"]*)" in the "([^"]*)" element, confirming the dialog$/
|
||||
*/
|
||||
public function iClickInTheElementConfirmingTheDialog($clickType, $text, $selector) {
|
||||
$this->iClickInTheElement($clickType, $text, $selector);
|
||||
$this->iConfirmTheDialog();
|
||||
}
|
||||
public function iClickInTheElementConfirmingTheDialog($clickType, $text, $selector)
|
||||
{
|
||||
$this->iClickInTheElement($clickType, $text, $selector);
|
||||
$this->iConfirmTheDialog();
|
||||
}
|
||||
/**
|
||||
* Needs to be in single command to avoid "unexpected alert open" errors in Selenium.
|
||||
* Example: I click "Delete" in the ".actions" element, dismissing the dialog
|
||||
*
|
||||
* @Given /^I (click|double click) "([^"]*)" in the "([^"]*)" element, dismissing the dialog$/
|
||||
*/
|
||||
public function iClickInTheElementDismissingTheDialog($clickType, $text, $selector) {
|
||||
$this->iClickInTheElement($clickType, $text, $selector);
|
||||
$this->iDismissTheDialog();
|
||||
}
|
||||
public function iClickInTheElementDismissingTheDialog($clickType, $text, $selector)
|
||||
{
|
||||
$this->iClickInTheElement($clickType, $text, $selector);
|
||||
$this->iDismissTheDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I type "([^"]*)" into the dialog$/
|
||||
*/
|
||||
public function iTypeIntoTheDialog($data) {
|
||||
public function iTypeIntoTheDialog($data)
|
||||
{
|
||||
$data = array(
|
||||
'text' => $data,
|
||||
);
|
||||
@ -430,7 +456,8 @@ JS;
|
||||
/**
|
||||
* @Given /^I confirm the dialog$/
|
||||
*/
|
||||
public function iConfirmTheDialog() {
|
||||
public function iConfirmTheDialog()
|
||||
{
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
|
||||
$this->handleAjaxTimeout();
|
||||
}
|
||||
@ -438,7 +465,8 @@ JS;
|
||||
/**
|
||||
* @Given /^I dismiss the dialog$/
|
||||
*/
|
||||
public function iDismissTheDialog() {
|
||||
public function iDismissTheDialog()
|
||||
{
|
||||
$this->getSession()->getDriver()->getWebDriverSession()->dismiss_alert();
|
||||
$this->handleAjaxTimeout();
|
||||
}
|
||||
@ -446,7 +474,8 @@ JS;
|
||||
/**
|
||||
* @Given /^(?:|I )attach the file "(?P<path>[^"]*)" to "(?P<field>(?:[^"]|\\")*)" with HTML5$/
|
||||
*/
|
||||
public function iAttachTheFileTo($field, $path) {
|
||||
public function iAttachTheFileTo($field, $path)
|
||||
{
|
||||
// Remove wrapped button styling to make input field accessible to Selenium
|
||||
$js = <<<JS
|
||||
var input = jQuery('[name="$field"]');
|
||||
@ -461,131 +490,151 @@ JS;
|
||||
return new Step\Given(sprintf('I attach the file "%s" to "%s"', $path, $field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select an individual input from within a group, matched by the top-most label.
|
||||
*
|
||||
* @Given /^I select "([^"]*)" from "([^"]*)" input group$/
|
||||
*/
|
||||
public function iSelectFromInputGroup($value, $labelText) {
|
||||
$page = $this->getSession()->getPage();
|
||||
$parent = null;
|
||||
/**
|
||||
* Select an individual input from within a group, matched by the top-most label.
|
||||
*
|
||||
* @Given /^I select "([^"]*)" from "([^"]*)" input group$/
|
||||
*/
|
||||
public function iSelectFromInputGroup($value, $labelText)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$parent = null;
|
||||
|
||||
foreach($page->findAll('css', 'label') as $label) {
|
||||
if($label->getText() == $labelText) {
|
||||
$parent = $label->getParent();
|
||||
}
|
||||
}
|
||||
foreach ($page->findAll('css', 'label') as $label) {
|
||||
if ($label->getText() == $labelText) {
|
||||
$parent = $label->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
if(!$parent) throw new \InvalidArgumentException(sprintf('Input group with label "%s" cannot be found', $labelText));
|
||||
if (!$parent) {
|
||||
throw new \InvalidArgumentException(sprintf('Input group with label "%s" cannot be found', $labelText));
|
||||
}
|
||||
|
||||
foreach($parent->findAll('css', 'label') as $option) {
|
||||
if($option->getText() == $value) {
|
||||
$input = null;
|
||||
foreach ($parent->findAll('css', 'label') as $option) {
|
||||
if ($option->getText() == $value) {
|
||||
$input = null;
|
||||
|
||||
// First, look for inputs referenced by the "for" element on this label
|
||||
$for = $option->getAttribute('for');
|
||||
if ($for) $input = $parent->findById($for);
|
||||
// First, look for inputs referenced by the "for" element on this label
|
||||
$for = $option->getAttribute('for');
|
||||
if ($for) {
|
||||
$input = $parent->findById($for);
|
||||
}
|
||||
|
||||
// Otherwise look for inputs _inside_ the label
|
||||
if (!$input) $input = $option->find('css', 'input');
|
||||
// Otherwise look for inputs _inside_ the label
|
||||
if (!$input) {
|
||||
$input = $option->find('css', 'input');
|
||||
}
|
||||
|
||||
if(!$input) throw new \InvalidArgumentException(sprintf('Input "%s" cannot be found', $value));
|
||||
if (!$input) {
|
||||
throw new \InvalidArgumentException(sprintf('Input "%s" cannot be found', $value));
|
||||
}
|
||||
|
||||
$this->getSession()->getDriver()->click($input->getXPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->getSession()->getDriver()->click($input->getXPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the scenario until the user presses a key. Useful when debugging a scenario.
|
||||
*
|
||||
* @Then /^(?:|I )put a breakpoint$/
|
||||
*/
|
||||
public function iPutABreakpoint() {
|
||||
public function iPutABreakpoint()
|
||||
{
|
||||
fwrite(STDOUT, "\033[s \033[93m[Breakpoint] Press \033[1;93m[RETURN]\033[0;93m to continue...\033[0m");
|
||||
while (fgets(STDIN, 1024) == '') {}
|
||||
while (fgets(STDIN, 1024) == '') {
|
||||
}
|
||||
fwrite(STDOUT, "\033[u");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms relative time statements compatible with strtotime().
|
||||
* Example: "time of 1 hour ago" might return "22:00:00" if its currently "23:00:00".
|
||||
* Customize through {@link setTimeFormat()}.
|
||||
*
|
||||
* @Transform /^(?:(the|a)) time of (?<val>.*)$/
|
||||
*/
|
||||
public function castRelativeToAbsoluteTime($prefix, $val) {
|
||||
$timestamp = strtotime($val);
|
||||
if(!$timestamp) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Can't resolve '%s' into a valid datetime value",
|
||||
$val
|
||||
));
|
||||
}
|
||||
return date($this->timeFormat, $timestamp);
|
||||
}
|
||||
/**
|
||||
* Transforms relative time statements compatible with strtotime().
|
||||
* Example: "time of 1 hour ago" might return "22:00:00" if its currently "23:00:00".
|
||||
* Customize through {@link setTimeFormat()}.
|
||||
*
|
||||
* @Transform /^(?:(the|a)) time of (?<val>.*)$/
|
||||
*/
|
||||
public function castRelativeToAbsoluteTime($prefix, $val)
|
||||
{
|
||||
$timestamp = strtotime($val);
|
||||
if (!$timestamp) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Can't resolve '%s' into a valid datetime value",
|
||||
$val
|
||||
));
|
||||
}
|
||||
return date($this->timeFormat, $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms relative date and time statements compatible with strtotime().
|
||||
* Example: "datetime of 2 days ago" might return "2013-10-10 22:00:00" if its currently
|
||||
* the 12th of October 2013. Customize through {@link setDatetimeFormat()}.
|
||||
*
|
||||
* @Transform /^(?:(the|a)) datetime of (?<val>.*)$/
|
||||
*/
|
||||
public function castRelativeToAbsoluteDatetime($prefix, $val) {
|
||||
$timestamp = strtotime($val);
|
||||
if(!$timestamp) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Can't resolve '%s' into a valid datetime value",
|
||||
$val
|
||||
));
|
||||
}
|
||||
return date($this->datetimeFormat, $timestamp);
|
||||
}
|
||||
/**
|
||||
* Transforms relative date and time statements compatible with strtotime().
|
||||
* Example: "datetime of 2 days ago" might return "2013-10-10 22:00:00" if its currently
|
||||
* the 12th of October 2013. Customize through {@link setDatetimeFormat()}.
|
||||
*
|
||||
* @Transform /^(?:(the|a)) datetime of (?<val>.*)$/
|
||||
*/
|
||||
public function castRelativeToAbsoluteDatetime($prefix, $val)
|
||||
{
|
||||
$timestamp = strtotime($val);
|
||||
if (!$timestamp) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Can't resolve '%s' into a valid datetime value",
|
||||
$val
|
||||
));
|
||||
}
|
||||
return date($this->datetimeFormat, $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms relative date statements compatible with strtotime().
|
||||
* Example: "date 2 days ago" might return "2013-10-10" if its currently
|
||||
* the 12th of October 2013. Customize through {@link setDateFormat()}.
|
||||
*
|
||||
* @Transform /^(?:(the|a)) date of (?<val>.*)$/
|
||||
*/
|
||||
public function castRelativeToAbsoluteDate($prefix, $val) {
|
||||
$timestamp = strtotime($val);
|
||||
if(!$timestamp) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Can't resolve '%s' into a valid datetime value",
|
||||
$val
|
||||
));
|
||||
}
|
||||
return date($this->dateFormat, $timestamp);
|
||||
}
|
||||
/**
|
||||
* Transforms relative date statements compatible with strtotime().
|
||||
* Example: "date 2 days ago" might return "2013-10-10" if its currently
|
||||
* the 12th of October 2013. Customize through {@link setDateFormat()}.
|
||||
*
|
||||
* @Transform /^(?:(the|a)) date of (?<val>.*)$/
|
||||
*/
|
||||
public function castRelativeToAbsoluteDate($prefix, $val)
|
||||
{
|
||||
$timestamp = strtotime($val);
|
||||
if (!$timestamp) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Can't resolve '%s' into a valid datetime value",
|
||||
$val
|
||||
));
|
||||
}
|
||||
return date($this->dateFormat, $timestamp);
|
||||
}
|
||||
|
||||
public function getDateFormat() {
|
||||
return $this->dateFormat;
|
||||
}
|
||||
public function getDateFormat()
|
||||
{
|
||||
return $this->dateFormat;
|
||||
}
|
||||
|
||||
public function setDateFormat($format) {
|
||||
$this->dateFormat = $format;
|
||||
}
|
||||
public function setDateFormat($format)
|
||||
{
|
||||
$this->dateFormat = $format;
|
||||
}
|
||||
|
||||
public function getTimeFormat() {
|
||||
return $this->timeFormat;
|
||||
}
|
||||
public function getTimeFormat()
|
||||
{
|
||||
return $this->timeFormat;
|
||||
}
|
||||
|
||||
public function setTimeFormat($format) {
|
||||
$this->timeFormat = $format;
|
||||
}
|
||||
public function setTimeFormat($format)
|
||||
{
|
||||
$this->timeFormat = $format;
|
||||
}
|
||||
|
||||
public function getDatetimeFormat() {
|
||||
return $this->datetimeFormat;
|
||||
}
|
||||
public function getDatetimeFormat()
|
||||
{
|
||||
return $this->datetimeFormat;
|
||||
}
|
||||
|
||||
public function setDatetimeFormat($format) {
|
||||
$this->datetimeFormat = $format;
|
||||
}
|
||||
public function setDatetimeFormat($format)
|
||||
{
|
||||
$this->datetimeFormat = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that field with specified in|name|label|value is disabled.
|
||||
@ -595,9 +644,10 @@ JS;
|
||||
* @Then /^the "(?P<name>(?:[^"]|\\")*)" (?P<type>(?:(field|button))) should (?P<negate>(?:(not |)))be disabled/
|
||||
* @Then /^the (?P<type>(?:(field|button))) "(?P<name>(?:[^"]|\\")*)" should (?P<negate>(?:(not |)))be disabled/
|
||||
*/
|
||||
public function stepFieldShouldBeDisabled($name, $type, $negate) {
|
||||
public function stepFieldShouldBeDisabled($name, $type, $negate)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
if($type == 'field') {
|
||||
if ($type == 'field') {
|
||||
$element = $page->findField($name);
|
||||
} else {
|
||||
$element = $page->find('named', array(
|
||||
@ -608,30 +658,31 @@ JS;
|
||||
assertNotNull($element, sprintf("Element '%s' not found", $name));
|
||||
|
||||
$disabledAttribute = $element->getAttribute('disabled');
|
||||
if(trim($negate)) {
|
||||
if (trim($negate)) {
|
||||
assertNull($disabledAttribute, sprintf("Failed asserting element '%s' is not disabled", $name));
|
||||
} else {
|
||||
assertNotNull($disabledAttribute, sprintf("Failed asserting element '%s' is disabled", $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that checkbox with specified in|name|label|value is enabled.
|
||||
* Example: Then the field "Email" should be enabled
|
||||
* Example: Then the "Email" field should be enabled
|
||||
*
|
||||
* @Then /^the "(?P<field>(?:[^"]|\\")*)" field should be enabled/
|
||||
* @Then /^the field "(?P<field>(?:[^"]|\\")*)" should be enabled/
|
||||
*/
|
||||
public function stepFieldShouldBeEnabled($field) {
|
||||
$page = $this->getSession()->getPage();
|
||||
$fieldElement = $page->findField($field);
|
||||
assertNotNull($fieldElement, sprintf("Field '%s' not found", $field));
|
||||
/**
|
||||
* Checks that checkbox with specified in|name|label|value is enabled.
|
||||
* Example: Then the field "Email" should be enabled
|
||||
* Example: Then the "Email" field should be enabled
|
||||
*
|
||||
* @Then /^the "(?P<field>(?:[^"]|\\")*)" field should be enabled/
|
||||
* @Then /^the field "(?P<field>(?:[^"]|\\")*)" should be enabled/
|
||||
*/
|
||||
public function stepFieldShouldBeEnabled($field)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$fieldElement = $page->findField($field);
|
||||
assertNotNull($fieldElement, sprintf("Field '%s' not found", $field));
|
||||
|
||||
$disabledAttribute = $fieldElement->getAttribute('disabled');
|
||||
$disabledAttribute = $fieldElement->getAttribute('disabled');
|
||||
|
||||
assertNull($disabledAttribute, sprintf("Failed asserting field '%s' is enabled", $field));
|
||||
}
|
||||
assertNull($disabledAttribute, sprintf("Failed asserting field '%s' is enabled", $field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks a link in a specific region (an element identified by a CSS selector, a "data-title" attribute,
|
||||
@ -642,14 +693,15 @@ JS;
|
||||
*
|
||||
* @Given /^I (?:follow|click) "(?P<link>[^"]*)" in the "(?P<region>[^"]*)" region$/
|
||||
*/
|
||||
public function iFollowInTheRegion($link, $region) {
|
||||
public function iFollowInTheRegion($link, $region)
|
||||
{
|
||||
$context = $this->getMainContext();
|
||||
$regionObj = $context->getRegionObj($region);
|
||||
assertNotNull($regionObj);
|
||||
|
||||
$linkObj = $regionObj->findLink($link);
|
||||
if (empty($linkObj)) {
|
||||
throw new \Exception(sprintf('The link "%s" was not found in the region "%s"
|
||||
throw new \Exception(sprintf('The link "%s" was not found in the region "%s"
|
||||
on the page %s', $link, $region, $this->getSession()->getCurrentUrl()));
|
||||
}
|
||||
|
||||
@ -663,14 +715,15 @@ JS;
|
||||
*
|
||||
* @Given /^I fill in "(?P<field>[^"]*)" with "(?P<value>[^"]*)" in the "(?P<region>[^"]*)" region$/
|
||||
*/
|
||||
public function iFillinTheRegion($field, $value, $region){
|
||||
public function iFillinTheRegion($field, $value, $region)
|
||||
{
|
||||
$context = $this->getMainContext();
|
||||
$regionObj = $context->getRegionObj($region);
|
||||
assertNotNull($regionObj, "Region Object is null");
|
||||
|
||||
$fieldObj = $regionObj->findField($field);
|
||||
if (empty($fieldObj)) {
|
||||
throw new \Exception(sprintf('The field "%s" was not found in the region "%s"
|
||||
throw new \Exception(sprintf('The field "%s" was not found in the region "%s"
|
||||
on the page %s', $field, $region, $this->getSession()->getCurrentUrl()));
|
||||
}
|
||||
|
||||
@ -688,7 +741,8 @@ JS;
|
||||
*
|
||||
* @Given /^I should (?P<negate>(?:(not |)))see "(?P<text>[^"]*)" in the "(?P<region>[^"]*)" region$/
|
||||
*/
|
||||
public function iSeeTextInRegion($negate, $text, $region) {
|
||||
public function iSeeTextInRegion($negate, $text, $region)
|
||||
{
|
||||
$context = $this->getMainContext();
|
||||
$regionObj = $context->getRegionObj($region);
|
||||
assertNotNull($regionObj);
|
||||
@ -697,7 +751,7 @@ JS;
|
||||
$actual = preg_replace('/\s+/u', ' ', $actual);
|
||||
$regex = '/'.preg_quote($text, '/').'/ui';
|
||||
|
||||
if(trim($negate)) {
|
||||
if (trim($negate)) {
|
||||
if (preg_match($regex, $actual)) {
|
||||
$message = sprintf(
|
||||
'The text "%s" was found in the text of the "%s" region on the page %s.',
|
||||
@ -720,27 +774,28 @@ JS;
|
||||
throw new \Exception($message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the specified radio button
|
||||
*
|
||||
* @Given /^I select the "([^"]*)" radio button$/
|
||||
*/
|
||||
public function iSelectTheRadioButton($radioLabel) {
|
||||
$session = $this->getSession();
|
||||
$radioButton = $session->getPage()->find('named', array(
|
||||
/**
|
||||
* Selects the specified radio button
|
||||
*
|
||||
* @Given /^I select the "([^"]*)" radio button$/
|
||||
*/
|
||||
public function iSelectTheRadioButton($radioLabel)
|
||||
{
|
||||
$session = $this->getSession();
|
||||
$radioButton = $session->getPage()->find('named', array(
|
||||
'radio', $this->getSession()->getSelectorsHandler()->xpathLiteral($radioLabel)
|
||||
));
|
||||
assertNotNull($radioButton);
|
||||
$session->getDriver()->click($radioButton->getXPath());
|
||||
}
|
||||
assertNotNull($radioButton);
|
||||
$session->getDriver()->click($radioButton->getXPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the "([^"]*)" table should contain "([^"]*)"$/
|
||||
*/
|
||||
public function theTableShouldContain($selector, $text) {
|
||||
public function theTableShouldContain($selector, $text)
|
||||
{
|
||||
$table = $this->getTable($selector);
|
||||
|
||||
$element = $table->find('named', array('content', "'$text'"));
|
||||
@ -750,7 +805,8 @@ JS;
|
||||
/**
|
||||
* @Then /^the "([^"]*)" table should not contain "([^"]*)"$/
|
||||
*/
|
||||
public function theTableShouldNotContain($selector, $text) {
|
||||
public function theTableShouldNotContain($selector, $text)
|
||||
{
|
||||
$table = $this->getTable($selector);
|
||||
|
||||
$element = $table->find('named', array('content', "'$text'"));
|
||||
@ -760,7 +816,8 @@ JS;
|
||||
/**
|
||||
* @Given /^I click on "([^"]*)" in the "([^"]*)" table$/
|
||||
*/
|
||||
public function iClickOnInTheTable($text, $selector) {
|
||||
public function iClickOnInTheTable($text, $selector)
|
||||
{
|
||||
$table = $this->getTable($selector);
|
||||
|
||||
$element = $table->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text));
|
||||
@ -778,22 +835,24 @@ JS;
|
||||
*
|
||||
* @return Behat\Mink\Element\NodeElement
|
||||
*/
|
||||
protected function getTable($selector) {
|
||||
protected function getTable($selector)
|
||||
{
|
||||
$selector = $this->getSession()->getSelectorsHandler()->xpathLiteral($selector);
|
||||
$page = $this->getSession()->getPage();
|
||||
$candidates = $page->findAll(
|
||||
'xpath',
|
||||
$this->getSession()->getSelectorsHandler()->selectorToXpath(
|
||||
"xpath", ".//table[(./@id = $selector or contains(./@title, $selector))]"
|
||||
"xpath",
|
||||
".//table[(./@id = $selector or contains(./@title, $selector))]"
|
||||
)
|
||||
);
|
||||
|
||||
// Find tables by a <caption> field
|
||||
$candidates += $page->findAll('xpath', "//table//caption[contains(normalize-space(string(.)),
|
||||
$candidates += $page->findAll('xpath', "//table//caption[contains(normalize-space(string(.)),
|
||||
$selector)]/ancestor-or-self::table[1]");
|
||||
|
||||
// Find tables by a .title node
|
||||
$candidates += $page->findAll('xpath', "//table//*[contains(concat(' ',normalize-space(@class),' '), ' title ') and contains(normalize-space(string(.)),
|
||||
$candidates += $page->findAll('xpath', "//table//*[contains(concat(' ',normalize-space(@class),' '), ' title ') and contains(normalize-space(string(.)),
|
||||
$selector)]/ancestor-or-self::table[1]");
|
||||
|
||||
// Some tables don't have a visible title, so look for a fieldset with data-name instead
|
||||
@ -802,8 +861,8 @@ JS;
|
||||
assertTrue((bool)$candidates, 'Could not find any table elements');
|
||||
|
||||
$table = null;
|
||||
foreach($candidates as $candidate) {
|
||||
if(!$table && $candidate->isVisible()) {
|
||||
foreach ($candidates as $candidate) {
|
||||
if (!$table && $candidate->isVisible()) {
|
||||
$table = $candidate;
|
||||
}
|
||||
}
|
||||
@ -813,49 +872,51 @@ JS;
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the order of two texts.
|
||||
* Assumptions: the two texts appear in their conjunct parent element once
|
||||
* @Then /^I should see the text "(?P<textBefore>(?:[^"]|\\")*)" (before|after) the text "(?P<textAfter>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/
|
||||
*/
|
||||
public function theTextBeforeAfter($textBefore, $order, $textAfter, $element) {
|
||||
$ele = $this->getSession()->getPage()->find('css', $element);
|
||||
assertNotNull($ele, sprintf('%s not found', $element));
|
||||
/**
|
||||
* Checks the order of two texts.
|
||||
* Assumptions: the two texts appear in their conjunct parent element once
|
||||
* @Then /^I should see the text "(?P<textBefore>(?:[^"]|\\")*)" (before|after) the text "(?P<textAfter>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/
|
||||
*/
|
||||
public function theTextBeforeAfter($textBefore, $order, $textAfter, $element)
|
||||
{
|
||||
$ele = $this->getSession()->getPage()->find('css', $element);
|
||||
assertNotNull($ele, sprintf('%s not found', $element));
|
||||
|
||||
// Check both of the texts exist in the element
|
||||
$text = $ele->getText();
|
||||
assertTrue(strpos($text, $textBefore) !== 'FALSE', sprintf('%s not found in the element %s', $textBefore, $element));
|
||||
assertTrue(strpos($text, $textAfter) !== 'FALSE', sprintf('%s not found in the element %s', $textAfter, $element));
|
||||
// Check both of the texts exist in the element
|
||||
$text = $ele->getText();
|
||||
assertTrue(strpos($text, $textBefore) !== 'FALSE', sprintf('%s not found in the element %s', $textBefore, $element));
|
||||
assertTrue(strpos($text, $textAfter) !== 'FALSE', sprintf('%s not found in the element %s', $textAfter, $element));
|
||||
|
||||
/// Use strpos to get the position of the first occurrence of the two texts (case-sensitive)
|
||||
// and compare them with the given order (before or after)
|
||||
if($order === 'before') {
|
||||
assertTrue(strpos($text, $textBefore) < strpos($text, $textAfter));
|
||||
} else {
|
||||
assertTrue(strpos($text, $textBefore) > strpos($text, $textAfter));
|
||||
}
|
||||
}
|
||||
/// Use strpos to get the position of the first occurrence of the two texts (case-sensitive)
|
||||
// and compare them with the given order (before or after)
|
||||
if ($order === 'before') {
|
||||
assertTrue(strpos($text, $textBefore) < strpos($text, $textAfter));
|
||||
} else {
|
||||
assertTrue(strpos($text, $textBefore) > strpos($text, $textAfter));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until a certain amount of seconds till I see an element identified by a CSS selector.
|
||||
*
|
||||
* Example: Given I wait for 10 seconds until I see the ".css_element" element
|
||||
*
|
||||
* @Given /^I wait for (\d+) seconds until I see the "([^"]*)" element$/
|
||||
**/
|
||||
public function iWaitXUntilISee($wait, $selector) {
|
||||
$page = $this->getSession()->getPage();
|
||||
/**
|
||||
* Wait until a certain amount of seconds till I see an element identified by a CSS selector.
|
||||
*
|
||||
* Example: Given I wait for 10 seconds until I see the ".css_element" element
|
||||
*
|
||||
* @Given /^I wait for (\d+) seconds until I see the "([^"]*)" element$/
|
||||
**/
|
||||
public function iWaitXUntilISee($wait, $selector)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$this->spin(function($page) use ($page, $selector){
|
||||
$element = $page->find('css', $selector);
|
||||
$this->spin(function ($page) use ($page, $selector) {
|
||||
$element = $page->find('css', $selector);
|
||||
|
||||
if(empty($element)) {
|
||||
return false;
|
||||
} else {
|
||||
return $element->isVisible();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (empty($element)) {
|
||||
return false;
|
||||
} else {
|
||||
return $element->isVisible();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until a particular element is visible, using a CSS selector. Useful for content loaded via AJAX, or only
|
||||
@ -865,13 +926,14 @@ JS;
|
||||
*
|
||||
* @Given /^I wait until I see the "([^"]*)" element$/
|
||||
*/
|
||||
public function iWaitUntilISee($selector) {
|
||||
public function iWaitUntilISee($selector)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$this->spin(function($page) use ($page, $selector){
|
||||
$this->spin(function ($page) use ($page, $selector) {
|
||||
$element = $page->find('css', $selector);
|
||||
if(empty($element)){
|
||||
if (empty($element)) {
|
||||
return false;
|
||||
} else{
|
||||
} else {
|
||||
return ($element->isVisible());
|
||||
}
|
||||
});
|
||||
@ -885,16 +947,17 @@ JS;
|
||||
*
|
||||
* @Given /^I wait until I see the text "([^"]*)"$/
|
||||
*/
|
||||
public function iWaitUntilISeeText($text){
|
||||
public function iWaitUntilISeeText($text)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$session = $this->getSession();
|
||||
$this->spin(function($page) use ($page, $session, $text) {
|
||||
$this->spin(function ($page) use ($page, $session, $text) {
|
||||
$element = $page->find(
|
||||
'xpath',
|
||||
$session->getSelectorsHandler()->selectorToXpath("xpath", ".//*[contains(text(), '$text')]")
|
||||
);
|
||||
|
||||
if(empty($element)) {
|
||||
if (empty($element)) {
|
||||
return false;
|
||||
} else {
|
||||
return ($element->isVisible());
|
||||
@ -902,64 +965,68 @@ JS;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I scroll to the bottom$/
|
||||
*/
|
||||
public function iScrollToBottom() {
|
||||
$javascript = 'window.scrollTo(0, Math.max(document.documentElement.scrollHeight, document.body.scrollHeight, document.documentElement.clientHeight));';
|
||||
$this->getSession()->executeScript($javascript);
|
||||
}
|
||||
/**
|
||||
* @Given /^I scroll to the bottom$/
|
||||
*/
|
||||
public function iScrollToBottom()
|
||||
{
|
||||
$javascript = 'window.scrollTo(0, Math.max(document.documentElement.scrollHeight, document.body.scrollHeight, document.documentElement.clientHeight));';
|
||||
$this->getSession()->executeScript($javascript);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^I scroll to the top$/
|
||||
*/
|
||||
public function iScrollToTop() {
|
||||
$this->getSession()->executeScript('window.scrollTo(0,0);');
|
||||
}
|
||||
/**
|
||||
* @Given /^I scroll to the top$/
|
||||
*/
|
||||
public function iScrollToTop()
|
||||
{
|
||||
$this->getSession()->executeScript('window.scrollTo(0,0);');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to a certain element by label.
|
||||
* Requires an "id" attribute to uniquely identify the element in the document.
|
||||
*
|
||||
* Example: Given I scroll to the "Submit" button
|
||||
* Example: Given I scroll to the "My Date" field
|
||||
*
|
||||
* @Given /^I scroll to the "([^"]*)" (field|link|button)$/
|
||||
*/
|
||||
public function iScrollToField($locator, $type) {
|
||||
$page = $this->getSession()->getPage();
|
||||
/**
|
||||
* Scroll to a certain element by label.
|
||||
* Requires an "id" attribute to uniquely identify the element in the document.
|
||||
*
|
||||
* Example: Given I scroll to the "Submit" button
|
||||
* Example: Given I scroll to the "My Date" field
|
||||
*
|
||||
* @Given /^I scroll to the "([^"]*)" (field|link|button)$/
|
||||
*/
|
||||
public function iScrollToField($locator, $type)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$el = $page->find('named', array($type, "'$locator'"));
|
||||
assertNotNull($el, sprintf('%s element not found', $locator));
|
||||
|
||||
$id = $el->getAttribute('id');
|
||||
if(empty($id)) {
|
||||
throw new \InvalidArgumentException('Element requires an "id" attribute');
|
||||
}
|
||||
if (empty($id)) {
|
||||
throw new \InvalidArgumentException('Element requires an "id" attribute');
|
||||
}
|
||||
|
||||
$js = sprintf("document.getElementById('%s').scrollIntoView(true);", $id);
|
||||
$this->getSession()->executeScript($js);
|
||||
}
|
||||
$js = sprintf("document.getElementById('%s').scrollIntoView(true);", $id);
|
||||
$this->getSession()->executeScript($js);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to a certain element by CSS selector.
|
||||
* Requires an "id" attribute to uniquely identify the element in the document.
|
||||
*
|
||||
* Example: Given I scroll to the ".css_element" element
|
||||
*
|
||||
* @Given /^I scroll to the "(?P<locator>(?:[^"]|\\")*)" element$/
|
||||
*/
|
||||
public function iScrollToElement($locator) {
|
||||
$el = $this->getSession()->getPage()->find('css', $locator);
|
||||
assertNotNull($el, sprintf('The element "%s" is not found', $locator));
|
||||
/**
|
||||
* Scroll to a certain element by CSS selector.
|
||||
* Requires an "id" attribute to uniquely identify the element in the document.
|
||||
*
|
||||
* Example: Given I scroll to the ".css_element" element
|
||||
*
|
||||
* @Given /^I scroll to the "(?P<locator>(?:[^"]|\\")*)" element$/
|
||||
*/
|
||||
public function iScrollToElement($locator)
|
||||
{
|
||||
$el = $this->getSession()->getPage()->find('css', $locator);
|
||||
assertNotNull($el, sprintf('The element "%s" is not found', $locator));
|
||||
|
||||
$id = $el->getAttribute('id');
|
||||
if(empty($id)) {
|
||||
throw new \InvalidArgumentException('Element requires an "id" attribute');
|
||||
}
|
||||
$id = $el->getAttribute('id');
|
||||
if (empty($id)) {
|
||||
throw new \InvalidArgumentException('Element requires an "id" attribute');
|
||||
}
|
||||
|
||||
$js = sprintf("document.getElementById('%s').scrollIntoView(true);", $id);
|
||||
$this->getSession()->executeScript($js);
|
||||
}
|
||||
$js = sprintf("document.getElementById('%s').scrollIntoView(true);", $id);
|
||||
$this->getSession()->executeScript($js);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuously poll the dom until callback returns true, code copied from
|
||||
@ -971,10 +1038,11 @@ JS;
|
||||
* @return bool Returns true if the lambda returns successfully
|
||||
* @throws \Exception Thrown if the wait threshold is exceeded without the lambda successfully returning
|
||||
*/
|
||||
public function spin($lambda, $wait = 60) {
|
||||
public function spin($lambda, $wait = 60)
|
||||
{
|
||||
for ($i = 0; $i < $wait; $i++) {
|
||||
try {
|
||||
if($lambda($this)) {
|
||||
if ($lambda($this)) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
@ -995,11 +1063,11 @@ JS;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* We have to catch exceptions and log somehow else otherwise behat falls over
|
||||
*/
|
||||
protected function logException($e){
|
||||
file_put_contents('php://stderr', 'Exception caught: '.$e);
|
||||
}
|
||||
|
||||
/**
|
||||
* We have to catch exceptions and log somehow else otherwise behat falls over
|
||||
*/
|
||||
protected function logException($e)
|
||||
{
|
||||
file_put_contents('php://stderr', 'Exception caught: '.$e);
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class ModuleContextClassGuesser implements ClassGuesserInterface
|
||||
// Try fully qualified namespace
|
||||
if (class_exists($class = $this->namespaceBase.'\\'.$this->namespaceSuffix.'\\'.$this->contextClass)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
// Fall back to namespace with SilverStripe prefix
|
||||
// TODO Remove once core has namespace capabilities for modules
|
||||
if (class_exists($class = 'SilverStripe\\'.$this->namespaceBase.'\\'.$this->namespaceSuffix.'\\'.$this->contextClass)) {
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Context;
|
||||
|
||||
use Behat\Behat\Context\ClosuredContextInterface,
|
||||
Behat\Behat\Context\TranslatedContextInterface,
|
||||
Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Event\FeatureEvent,
|
||||
Behat\Behat\Event\ScenarioEvent,
|
||||
Behat\Behat\Exception\PendingException;
|
||||
use Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
use Behat\Behat\Context\ClosuredContextInterface;
|
||||
use Behat\Behat\Context\TranslatedContextInterface;
|
||||
use Behat\Behat\Context\BehatContext;
|
||||
use Behat\Behat\Context\Step;
|
||||
use Behat\Behat\Event\FeatureEvent;
|
||||
use Behat\Behat\Event\ScenarioEvent;
|
||||
use Behat\Behat\Exception\PendingException;
|
||||
use Behat\Gherkin\Node\PyStringNode;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
// PHPUnit
|
||||
@ -59,7 +59,7 @@ class EmailContext extends BehatContext
|
||||
// to ensure its available both in CLI execution and the tested browser session
|
||||
$this->mailer = new \SilverStripe\BehatExtension\Utility\TestMailer();
|
||||
\Email::set_mailer($this->mailer);
|
||||
\Config::inst()->update("Email","send_all_emails_to", null);
|
||||
\Config::inst()->update("Email", "send_all_emails_to", null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,7 +70,7 @@ class EmailContext extends BehatContext
|
||||
$to = ($direction == 'to') ? $email : null;
|
||||
$from = ($direction == 'from') ? $email : null;
|
||||
$match = $this->mailer->findEmail($to, $from);
|
||||
if(trim($negate)) {
|
||||
if (trim($negate)) {
|
||||
assertNull($match);
|
||||
} else {
|
||||
assertNotNull($match);
|
||||
@ -87,8 +87,10 @@ class EmailContext extends BehatContext
|
||||
$from = ($direction == 'from') ? $email : null;
|
||||
$match = $this->mailer->findEmail($to, $from, $subject);
|
||||
$allMails = $this->mailer->findEmails($to, $from);
|
||||
$allTitles = $allMails ? '"' . implode('","', array_map(function($email) {return $email->Subject;}, $allMails)) . '"' : null;
|
||||
if(trim($negate)) {
|
||||
$allTitles = $allMails ? '"' . implode('","', array_map(function ($email) {
|
||||
return $email->Subject;
|
||||
}, $allMails)) . '"' : null;
|
||||
if (trim($negate)) {
|
||||
assertNull($match);
|
||||
} else {
|
||||
$msg = sprintf(
|
||||
@ -97,10 +99,10 @@ class EmailContext extends BehatContext
|
||||
$email,
|
||||
$subject
|
||||
);
|
||||
if($allTitles) {
|
||||
if ($allTitles) {
|
||||
$msg .= ' Existing emails: ' . $allTitles;
|
||||
}
|
||||
assertNotNull($match,$msg);
|
||||
assertNotNull($match, $msg);
|
||||
}
|
||||
$this->lastMatchedEmail = $match;
|
||||
}
|
||||
@ -109,51 +111,51 @@ class EmailContext extends BehatContext
|
||||
* Example: Given the email should contain "Thank you for registering!".
|
||||
* Assumes an email has been identified by a previous step,
|
||||
* e.g. through 'Given there should be an email to "test@test.com"'.
|
||||
*
|
||||
* @Given /^the email should (not |)contain "([^"]*)"$/
|
||||
*/
|
||||
public function thereTheEmailContains($negate, $content)
|
||||
{
|
||||
if(!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
*
|
||||
* @Given /^the email should (not |)contain "([^"]*)"$/
|
||||
*/
|
||||
public function thereTheEmailContains($negate, $content)
|
||||
{
|
||||
if (!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
|
||||
$email = $this->lastMatchedEmail;
|
||||
$emailContent = null;
|
||||
if($email->Content) {
|
||||
$emailContent = $email->Content;
|
||||
} else {
|
||||
$emailContent = $email->PlainContent;
|
||||
}
|
||||
$email = $this->lastMatchedEmail;
|
||||
$emailContent = null;
|
||||
if ($email->Content) {
|
||||
$emailContent = $email->Content;
|
||||
} else {
|
||||
$emailContent = $email->PlainContent;
|
||||
}
|
||||
|
||||
if(trim($negate)) {
|
||||
assertNotContains($content, $emailContent);
|
||||
} else {
|
||||
assertContains($content, $emailContent);
|
||||
}
|
||||
}
|
||||
if (trim($negate)) {
|
||||
assertNotContains($content, $emailContent);
|
||||
} else {
|
||||
assertContains($content, $emailContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given the email contains "Thank you for <strong>registering!<strong>".
|
||||
* Then the email should contain plain text "Thank you for registering!"
|
||||
* Assumes an email has been identified by a previous step,
|
||||
* e.g. through 'Given there should be an email to "test@test.com"'.
|
||||
*
|
||||
* @Given /^the email should contain plain text "([^"]*)"$/
|
||||
*/
|
||||
public function thereTheEmailContainsPlainText($content)
|
||||
{
|
||||
if(!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
/**
|
||||
* Example: Given the email contains "Thank you for <strong>registering!<strong>".
|
||||
* Then the email should contain plain text "Thank you for registering!"
|
||||
* Assumes an email has been identified by a previous step,
|
||||
* e.g. through 'Given there should be an email to "test@test.com"'.
|
||||
*
|
||||
* @Given /^the email should contain plain text "([^"]*)"$/
|
||||
*/
|
||||
public function thereTheEmailContainsPlainText($content)
|
||||
{
|
||||
if (!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
|
||||
$email = $this->lastMatchedEmail;
|
||||
$emailContent = ($email->Content) ? ($email->Content) : ($email->PlainContent);
|
||||
$emailPlainText = strip_tags($emailContent);
|
||||
$emailPlainText = preg_replace("/\h+/", " ", $emailPlainText);
|
||||
$email = $this->lastMatchedEmail;
|
||||
$emailContent = ($email->Content) ? ($email->Content) : ($email->PlainContent);
|
||||
$emailPlainText = strip_tags($emailContent);
|
||||
$emailPlainText = preg_replace("/\h+/", " ", $emailPlainText);
|
||||
|
||||
assertContains($content, $emailPlainText);
|
||||
}
|
||||
assertContains($content, $emailPlainText);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I click on the "([^"]*)" link in the email (to|from) "([^"]*)"$/
|
||||
@ -195,12 +197,12 @@ class EmailContext extends BehatContext
|
||||
/**
|
||||
* Assumes an email has been identified by a previous step,
|
||||
* e.g. through 'Given there should be an email to "test@test.com"'.
|
||||
*
|
||||
*
|
||||
* @When /^I click on the "([^"]*)" link in the email"$/
|
||||
*/
|
||||
public function iGoToInTheEmail($linkSelector)
|
||||
{
|
||||
if(!$this->lastMatchedEmail) {
|
||||
if (!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
|
||||
@ -223,91 +225,92 @@ class EmailContext extends BehatContext
|
||||
return $this->mailer->clearEmails();
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Then the email should contain the following data:
|
||||
* | row1 |
|
||||
* | row2 |
|
||||
* Assumes an email has been identified by a previous step.
|
||||
* @Then /^the email should (not |)contain the following data:$/
|
||||
*/
|
||||
public function theEmailContainFollowingData($negate, TableNode $table) {
|
||||
if(!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
/**
|
||||
* Example: Then the email should contain the following data:
|
||||
* | row1 |
|
||||
* | row2 |
|
||||
* Assumes an email has been identified by a previous step.
|
||||
* @Then /^the email should (not |)contain the following data:$/
|
||||
*/
|
||||
public function theEmailContainFollowingData($negate, TableNode $table)
|
||||
{
|
||||
if (!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
|
||||
$email = $this->lastMatchedEmail;
|
||||
$emailContent = null;
|
||||
if($email->Content) {
|
||||
$emailContent = $email->Content;
|
||||
} else {
|
||||
$emailContent = $email->PlainContent;
|
||||
}
|
||||
// Convert html content to plain text
|
||||
$emailContent = strip_tags($emailContent);
|
||||
$emailContent = preg_replace("/\h+/", " ", $emailContent);
|
||||
$rows = $table->getRows();
|
||||
|
||||
// For "should not contain"
|
||||
if(trim($negate)) {
|
||||
foreach($rows as $row) {
|
||||
assertNotContains($row[0], $emailContent);
|
||||
}
|
||||
} else {
|
||||
foreach($rows as $row) {
|
||||
assertContains($row[0], $emailContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
$email = $this->lastMatchedEmail;
|
||||
$emailContent = null;
|
||||
if ($email->Content) {
|
||||
$emailContent = $email->Content;
|
||||
} else {
|
||||
$emailContent = $email->PlainContent;
|
||||
}
|
||||
// Convert html content to plain text
|
||||
$emailContent = strip_tags($emailContent);
|
||||
$emailContent = preg_replace("/\h+/", " ", $emailContent);
|
||||
$rows = $table->getRows();
|
||||
|
||||
// For "should not contain"
|
||||
if (trim($negate)) {
|
||||
foreach ($rows as $row) {
|
||||
assertNotContains($row[0], $emailContent);
|
||||
}
|
||||
} else {
|
||||
foreach ($rows as $row) {
|
||||
assertContains($row[0], $emailContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^there should (not |)be an email titled "([^"]*)"$/
|
||||
*/
|
||||
public function thereIsAnEmailTitled($negate, $subject)
|
||||
{
|
||||
$match = $this->mailer->findEmail(null, null, $subject);
|
||||
if(trim($negate)) {
|
||||
assertNull($match);
|
||||
} else {
|
||||
$msg = sprintf(
|
||||
'Could not find email titled "%s".',
|
||||
$subject
|
||||
);
|
||||
assertNotNull($match,$msg);
|
||||
}
|
||||
$this->lastMatchedEmail = $match;
|
||||
}
|
||||
/**
|
||||
* @Then /^there should (not |)be an email titled "([^"]*)"$/
|
||||
*/
|
||||
public function thereIsAnEmailTitled($negate, $subject)
|
||||
{
|
||||
$match = $this->mailer->findEmail(null, null, $subject);
|
||||
if (trim($negate)) {
|
||||
assertNull($match);
|
||||
} else {
|
||||
$msg = sprintf(
|
||||
'Could not find email titled "%s".',
|
||||
$subject
|
||||
);
|
||||
assertNotNull($match, $msg);
|
||||
}
|
||||
$this->lastMatchedEmail = $match;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the email should (not |)be sent from "([^"]*)"$/
|
||||
*/
|
||||
public function theEmailSentFrom($negate, $from)
|
||||
{
|
||||
if(!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
/**
|
||||
* @Then /^the email should (not |)be sent from "([^"]*)"$/
|
||||
*/
|
||||
public function theEmailSentFrom($negate, $from)
|
||||
{
|
||||
if (!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
|
||||
$match = $this->lastMatchedEmail;
|
||||
if(trim($negate)) {
|
||||
assertNotContains($from, $match->From);
|
||||
} else {
|
||||
assertContains($from, $match->From);
|
||||
}
|
||||
}
|
||||
$match = $this->lastMatchedEmail;
|
||||
if (trim($negate)) {
|
||||
assertNotContains($from, $match->From);
|
||||
} else {
|
||||
assertContains($from, $match->From);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the email should (not |)be sent to "([^"]*)"$/
|
||||
*/
|
||||
public function theEmailSentTo($negate, $to)
|
||||
{
|
||||
if(!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
/**
|
||||
* @Then /^the email should (not |)be sent to "([^"]*)"$/
|
||||
*/
|
||||
public function theEmailSentTo($negate, $to)
|
||||
{
|
||||
if (!$this->lastMatchedEmail) {
|
||||
throw new \LogicException('No matched email found from previous step');
|
||||
}
|
||||
|
||||
$match = $this->lastMatchedEmail;
|
||||
if(trim($negate)) {
|
||||
assertNotContains($to, $match->To);
|
||||
} else {
|
||||
assertContains($to, $match->To);
|
||||
}
|
||||
}
|
||||
$match = $this->lastMatchedEmail;
|
||||
if (trim($negate)) {
|
||||
assertNotContains($to, $match->To);
|
||||
} else {
|
||||
assertContains($to, $match->To);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,16 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Context;
|
||||
|
||||
use Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Event\ScenarioEvent,
|
||||
Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Gherkin\Node\TableNode,
|
||||
SilverStripe\Filesystem\Storage\AssetStore;
|
||||
use Behat\Behat\Context\BehatContext;
|
||||
use Behat\Behat\Event\ScenarioEvent;
|
||||
use Behat\Gherkin\Node\PyStringNode;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use SilverStripe\Filesystem\Storage\AssetStore;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\Versioning\Versioned;
|
||||
use SilverStripe\Security\Permission;
|
||||
|
||||
|
||||
|
||||
// PHPUnit
|
||||
require_once BASE_PATH . '/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php';
|
||||
|
||||
@ -22,649 +20,711 @@ require_once BASE_PATH . '/vendor/phpunit/phpunit/src/Framework/Assert/Functions
|
||||
*/
|
||||
class FixtureContext extends BehatContext
|
||||
{
|
||||
protected $context;
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* @var \FixtureFactory
|
||||
*/
|
||||
protected $fixtureFactory;
|
||||
/**
|
||||
* @var \FixtureFactory
|
||||
*/
|
||||
protected $fixtureFactory;
|
||||
|
||||
/**
|
||||
* @var String Absolute path where file fixtures are located.
|
||||
* These will automatically get copied to their location
|
||||
* declare through the 'Given a file "..."' step defition.
|
||||
*/
|
||||
protected $filesPath;
|
||||
/**
|
||||
* @var String Absolute path where file fixtures are located.
|
||||
* These will automatically get copied to their location
|
||||
* declare through the 'Given a file "..."' step defition.
|
||||
*/
|
||||
protected $filesPath;
|
||||
|
||||
/**
|
||||
* @var String Tracks all files and folders created from fixtures, for later cleanup.
|
||||
*/
|
||||
protected $createdFilesPaths = array();
|
||||
/**
|
||||
* @var String Tracks all files and folders created from fixtures, for later cleanup.
|
||||
*/
|
||||
protected $createdFilesPaths = array();
|
||||
|
||||
/**
|
||||
* @var array Stores the asset tuples.
|
||||
*/
|
||||
protected $createdAssets = array();
|
||||
/**
|
||||
* @var array Stores the asset tuples.
|
||||
*/
|
||||
protected $createdAssets = array();
|
||||
|
||||
public function __construct(array $parameters) {
|
||||
$this->context = $parameters;
|
||||
}
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->context = $parameters;
|
||||
}
|
||||
|
||||
public function getSession($name = null) {
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
public function getSession($name = null)
|
||||
{
|
||||
return $this->getMainContext()->getSession($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FixtureFactory
|
||||
*/
|
||||
public function getFixtureFactory() {
|
||||
if(!$this->fixtureFactory) {
|
||||
$this->fixtureFactory = \Injector::inst()->create('FixtureFactory', 'FixtureContextFactory');
|
||||
}
|
||||
return $this->fixtureFactory;
|
||||
}
|
||||
/**
|
||||
* @return \FixtureFactory
|
||||
*/
|
||||
public function getFixtureFactory()
|
||||
{
|
||||
if (!$this->fixtureFactory) {
|
||||
$this->fixtureFactory = \Injector::inst()->create('FixtureFactory', 'FixtureContextFactory');
|
||||
}
|
||||
return $this->fixtureFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \FixtureFactory $factory
|
||||
*/
|
||||
public function setFixtureFactory(\FixtureFactory $factory) {
|
||||
$this->fixtureFactory = $factory;
|
||||
}
|
||||
/**
|
||||
* @param \FixtureFactory $factory
|
||||
*/
|
||||
public function setFixtureFactory(\FixtureFactory $factory)
|
||||
{
|
||||
$this->fixtureFactory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String
|
||||
*/
|
||||
public function setFilesPath($path) {
|
||||
$this->filesPath = $path;
|
||||
}
|
||||
/**
|
||||
* @param String
|
||||
*/
|
||||
public function setFilesPath($path)
|
||||
{
|
||||
$this->filesPath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
public function getFilesPath() {
|
||||
return $this->filesPath;
|
||||
}
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
public function getFilesPath()
|
||||
{
|
||||
return $this->filesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario @database-defaults
|
||||
*/
|
||||
public function beforeDatabaseDefaults(ScenarioEvent $event) {
|
||||
\SapphireTest::empty_temp_db();
|
||||
DB::get_conn()->quiet();
|
||||
$dataClasses = \ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject');
|
||||
array_shift($dataClasses);
|
||||
foreach ($dataClasses as $dataClass) {
|
||||
\singleton($dataClass)->requireDefaultRecords();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @BeforeScenario @database-defaults
|
||||
*/
|
||||
public function beforeDatabaseDefaults(ScenarioEvent $event)
|
||||
{
|
||||
\SapphireTest::empty_temp_db();
|
||||
DB::get_conn()->quiet();
|
||||
$dataClasses = \ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject');
|
||||
array_shift($dataClasses);
|
||||
foreach ($dataClasses as $dataClass) {
|
||||
\singleton($dataClass)->requireDefaultRecords();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function afterResetDatabase(ScenarioEvent $event) {
|
||||
\SapphireTest::empty_temp_db();
|
||||
}
|
||||
public function afterResetDatabase(ScenarioEvent $event)
|
||||
{
|
||||
\SapphireTest::empty_temp_db();
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function afterResetAssets(ScenarioEvent $event) {
|
||||
$store = $this->getAssetStore();
|
||||
if (is_array($this->createdAssets)) {
|
||||
foreach ($this->createdAssets as $asset) {
|
||||
$store->delete($asset['FileFilename'], $asset['FileHash']);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function afterResetAssets(ScenarioEvent $event)
|
||||
{
|
||||
$store = $this->getAssetStore();
|
||||
if (is_array($this->createdAssets)) {
|
||||
foreach ($this->createdAssets as $asset) {
|
||||
$store->delete($asset['FileFilename'], $asset['FileHash']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a "page" "Page 1"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)"$/
|
||||
*/
|
||||
public function stepCreateRecord($type, $id) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$fields = $this->prepareFixture($class, $id);
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
/**
|
||||
* Example: Given a "page" "Page 1"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)"$/
|
||||
*/
|
||||
public function stepCreateRecord($type, $id)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$fields = $this->prepareFixture($class, $id);
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a "page" "Page 1" has the "content" "My content"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" has (?:(an|a|the) )"(?<field>.*)" "(?<value>.*)"$/
|
||||
*/
|
||||
public function stepCreateRecordHasField($type, $id, $field, $value) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$fields = $this->convertFields(
|
||||
$class,
|
||||
array($field => $value)
|
||||
);
|
||||
// We should check if this fixture object already exists - if it does, we update it. If not, we create it
|
||||
if($existingFixture = $this->fixtureFactory->get($class, $id)) {
|
||||
// Merge existing data with new data, and create new object to replace existing object
|
||||
foreach($fields as $k => $v) {
|
||||
$existingFixture->$k = $v;
|
||||
}
|
||||
$existingFixture->write();
|
||||
} else {
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Example: Given a "page" "Page 1" has the "content" "My content"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" has (?:(an|a|the) )"(?<field>.*)" "(?<value>.*)"$/
|
||||
*/
|
||||
public function stepCreateRecordHasField($type, $id, $field, $value)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$fields = $this->convertFields(
|
||||
$class,
|
||||
array($field => $value)
|
||||
);
|
||||
// We should check if this fixture object already exists - if it does, we update it. If not, we create it
|
||||
if ($existingFixture = $this->fixtureFactory->get($class, $id)) {
|
||||
// Merge existing data with new data, and create new object to replace existing object
|
||||
foreach ($fields as $k => $v) {
|
||||
$existingFixture->$k = $v;
|
||||
}
|
||||
$existingFixture->write();
|
||||
} else {
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a "page" "Page 1" with "URL"="page-1" and "Content"="my page 1"
|
||||
* Example: Given the "page" "Page 1" has "URL"="page-1" and "Content"="my page 1"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" (?:(with|has)) (?<data>".*)$/
|
||||
*/
|
||||
public function stepCreateRecordWithData($type, $id, $data) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
preg_match_all(
|
||||
'/"(?<key>[^"]+)"\s*=\s*"(?<value>[^"]+)"/',
|
||||
$data,
|
||||
$matches
|
||||
);
|
||||
$fields = $this->convertFields(
|
||||
$class,
|
||||
array_combine($matches['key'], $matches['value'])
|
||||
);
|
||||
$fields = $this->prepareFixture($class, $id, $fields);
|
||||
// We should check if this fixture object already exists - if it does, we update it. If not, we create it
|
||||
if($existingFixture = $this->fixtureFactory->get($class, $id)) {
|
||||
// Merge existing data with new data, and create new object to replace existing object
|
||||
foreach($fields as $k => $v) {
|
||||
$existingFixture->$k = $v;
|
||||
}
|
||||
$existingFixture->write();
|
||||
} else {
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Example: Given a "page" "Page 1" with "URL"="page-1" and "Content"="my page 1"
|
||||
* Example: Given the "page" "Page 1" has "URL"="page-1" and "Content"="my page 1"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" (?:(with|has)) (?<data>".*)$/
|
||||
*/
|
||||
public function stepCreateRecordWithData($type, $id, $data)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
preg_match_all(
|
||||
'/"(?<key>[^"]+)"\s*=\s*"(?<value>[^"]+)"/',
|
||||
$data,
|
||||
$matches
|
||||
);
|
||||
$fields = $this->convertFields(
|
||||
$class,
|
||||
array_combine($matches['key'], $matches['value'])
|
||||
);
|
||||
$fields = $this->prepareFixture($class, $id, $fields);
|
||||
// We should check if this fixture object already exists - if it does, we update it. If not, we create it
|
||||
if ($existingFixture = $this->fixtureFactory->get($class, $id)) {
|
||||
// Merge existing data with new data, and create new object to replace existing object
|
||||
foreach ($fields as $k => $v) {
|
||||
$existingFixture->$k = $v;
|
||||
}
|
||||
$existingFixture->write();
|
||||
} else {
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: And the "page" "Page 2" has the following data
|
||||
* | Content | <blink> |
|
||||
* | My Property | foo |
|
||||
* | My Boolean | bar |
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" has the following data$/
|
||||
*/
|
||||
public function stepCreateRecordWithTable($type, $id, $null, TableNode $fieldsTable) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
// TODO Support more than one record
|
||||
$fields = $this->convertFields($class, $fieldsTable->getRowsHash());
|
||||
$fields = $this->prepareFixture($class, $id, $fields);
|
||||
/**
|
||||
* Example: And the "page" "Page 2" has the following data
|
||||
* | Content | <blink> |
|
||||
* | My Property | foo |
|
||||
* | My Boolean | bar |
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" has the following data$/
|
||||
*/
|
||||
public function stepCreateRecordWithTable($type, $id, $null, TableNode $fieldsTable)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
// TODO Support more than one record
|
||||
$fields = $this->convertFields($class, $fieldsTable->getRowsHash());
|
||||
$fields = $this->prepareFixture($class, $id, $fields);
|
||||
|
||||
// We should check if this fixture object already exists - if it does, we update it. If not, we create it
|
||||
if($existingFixture = $this->fixtureFactory->get($class, $id)) {
|
||||
// Merge existing data with new data, and create new object to replace existing object
|
||||
foreach($fields as $k => $v) {
|
||||
$existingFixture->$k = $v;
|
||||
}
|
||||
$existingFixture->write();
|
||||
} else {
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
}
|
||||
// We should check if this fixture object already exists - if it does, we update it. If not, we create it
|
||||
if ($existingFixture = $this->fixtureFactory->get($class, $id)) {
|
||||
// Merge existing data with new data, and create new object to replace existing object
|
||||
foreach ($fields as $k => $v) {
|
||||
$existingFixture->$k = $v;
|
||||
}
|
||||
$existingFixture->write();
|
||||
} else {
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given the "page" "Page 1.1" is a child of the "page" "Page1".
|
||||
* Note that this change is not published by default
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" is a (?<relation>[^\s]*) of (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)"/
|
||||
*/
|
||||
public function stepUpdateRecordRelation($type, $id, $relation, $relationType, $relationId) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
/**
|
||||
* Example: Given the "page" "Page 1.1" is a child of the "page" "Page1".
|
||||
* Note that this change is not published by default
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" is a (?<relation>[^\s]*) of (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)"/
|
||||
*/
|
||||
public function stepUpdateRecordRelation($type, $id, $relation, $relationType, $relationId)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
|
||||
$relationClass = $this->convertTypeToClass($relationType);
|
||||
$relationObj = $this->fixtureFactory->get($relationClass, $relationId);
|
||||
if(!$relationObj) $relationObj = $this->fixtureFactory->createObject($relationClass, $relationId);
|
||||
$relationClass = $this->convertTypeToClass($relationType);
|
||||
$relationObj = $this->fixtureFactory->get($relationClass, $relationId);
|
||||
if (!$relationObj) {
|
||||
$relationObj = $this->fixtureFactory->createObject($relationClass, $relationId);
|
||||
}
|
||||
|
||||
$data = array();
|
||||
if($relation == 'child') {
|
||||
$data['ParentID'] = $relationObj->ID;
|
||||
}
|
||||
$data = array();
|
||||
if ($relation == 'child') {
|
||||
$data['ParentID'] = $relationObj->ID;
|
||||
}
|
||||
|
||||
$obj = $this->fixtureFactory->get($class, $id);
|
||||
if($obj) {
|
||||
$obj->update($data);
|
||||
$obj->write();
|
||||
} else {
|
||||
$obj = $this->fixtureFactory->createObject($class, $id, $data);
|
||||
}
|
||||
$obj = $this->fixtureFactory->get($class, $id);
|
||||
if ($obj) {
|
||||
$obj->update($data);
|
||||
$obj->write();
|
||||
} else {
|
||||
$obj = $this->fixtureFactory->createObject($class, $id, $data);
|
||||
}
|
||||
|
||||
switch($relation) {
|
||||
case 'parent':
|
||||
$relationObj->ParentID = $obj->ID;
|
||||
$relationObj->write();
|
||||
break;
|
||||
case 'child':
|
||||
// already written through $data above
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid relation "%s"', $relation
|
||||
));
|
||||
}
|
||||
}
|
||||
switch ($relation) {
|
||||
case 'parent':
|
||||
$relationObj->ParentID = $obj->ID;
|
||||
$relationObj->write();
|
||||
break;
|
||||
case 'child':
|
||||
// already written through $data above
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid relation "%s"',
|
||||
$relation
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a type of object to another type of object. The base object will be created if it does not exist already.
|
||||
* If the last part of the string (in the "X" relation) is omitted, then the first matching relation will be used.
|
||||
*
|
||||
* @example I assign the "TaxonomyTerm" "For customers" to the "Page" "Page1"
|
||||
* @Given /^I assign (?:(an|a|the) )"(?<type>[^"]+)" "(?<value>[^"]+)" to (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)"$/
|
||||
*/
|
||||
public function stepIAssignObjToObj($type, $value, $relationType, $relationId) {
|
||||
self::stepIAssignObjToObjInTheRelation($type, $value, $relationType, $relationId, null);
|
||||
}
|
||||
/**
|
||||
* Assign a type of object to another type of object. The base object will be created if it does not exist already.
|
||||
* If the last part of the string (in the "X" relation) is omitted, then the first matching relation will be used.
|
||||
*
|
||||
* @example I assign the "TaxonomyTerm" "For customers" to the "Page" "Page1"
|
||||
* @Given /^I assign (?:(an|a|the) )"(?<type>[^"]+)" "(?<value>[^"]+)" to (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)"$/
|
||||
*/
|
||||
public function stepIAssignObjToObj($type, $value, $relationType, $relationId)
|
||||
{
|
||||
self::stepIAssignObjToObjInTheRelation($type, $value, $relationType, $relationId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a type of object to another type of object. The base object will be created if it does not exist already.
|
||||
* If the last part of the string (in the "X" relation) is omitted, then the first matching relation will be used.
|
||||
* Assumption: one object has relationship (has_one, has_many or many_many ) with the other object
|
||||
*
|
||||
* @example I assign the "TaxonomyTerm" "For customers" to the "Page" "Page1" in the "Terms" relation
|
||||
* @Given /^I assign (?:(an|a|the) )"(?<type>[^"]+)" "(?<value>[^"]+)" to (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)" in the "(?<relationName>[^"]+)" relation$/
|
||||
*/
|
||||
public function stepIAssignObjToObjInTheRelation($type, $value, $relationType, $relationId, $relationName) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$relationClass = $this->convertTypeToClass($relationType);
|
||||
/**
|
||||
* Assign a type of object to another type of object. The base object will be created if it does not exist already.
|
||||
* If the last part of the string (in the "X" relation) is omitted, then the first matching relation will be used.
|
||||
* Assumption: one object has relationship (has_one, has_many or many_many ) with the other object
|
||||
*
|
||||
* @example I assign the "TaxonomyTerm" "For customers" to the "Page" "Page1" in the "Terms" relation
|
||||
* @Given /^I assign (?:(an|a|the) )"(?<type>[^"]+)" "(?<value>[^"]+)" to (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)" in the "(?<relationName>[^"]+)" relation$/
|
||||
*/
|
||||
public function stepIAssignObjToObjInTheRelation($type, $value, $relationType, $relationId, $relationName)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$relationClass = $this->convertTypeToClass($relationType);
|
||||
|
||||
// Check if this fixture object already exists - if not, we create it
|
||||
$relationObj = $this->fixtureFactory->get($relationClass, $relationId);
|
||||
if(!$relationObj) $relationObj = $this->fixtureFactory->createObject($relationClass, $relationId);
|
||||
// Check if this fixture object already exists - if not, we create it
|
||||
$relationObj = $this->fixtureFactory->get($relationClass, $relationId);
|
||||
if (!$relationObj) {
|
||||
$relationObj = $this->fixtureFactory->createObject($relationClass, $relationId);
|
||||
}
|
||||
|
||||
// Check if there is relationship defined in many_many (includes belongs_many_many)
|
||||
$manyField = null;
|
||||
$oneField = null;
|
||||
if ($relationObj->many_many()) {
|
||||
$manyField = array_search($class, $relationObj->many_many());
|
||||
if($manyField && strlen($relationName) > 0) $manyField = $relationName;
|
||||
}
|
||||
if(empty($manyField) && $relationObj->has_many()) {
|
||||
$manyField = array_search($class, $relationObj->has_many());
|
||||
if($manyField && strlen($relationName) > 0) $manyField = $relationName;
|
||||
}
|
||||
if(empty($manyField) && $relationObj->has_one()) {
|
||||
$oneField = array_search($class, $relationObj->has_one());
|
||||
if($oneField && strlen($relationName) > 0) $oneField = $relationName;
|
||||
}
|
||||
if(empty($manyField) && empty($oneField)) {
|
||||
throw new \Exception("'$relationClass' has no relationship (has_one, has_many and many_many) with '$class'!");
|
||||
}
|
||||
// Check if there is relationship defined in many_many (includes belongs_many_many)
|
||||
$manyField = null;
|
||||
$oneField = null;
|
||||
if ($relationObj->many_many()) {
|
||||
$manyField = array_search($class, $relationObj->many_many());
|
||||
if ($manyField && strlen($relationName) > 0) {
|
||||
$manyField = $relationName;
|
||||
}
|
||||
}
|
||||
if (empty($manyField) && $relationObj->has_many()) {
|
||||
$manyField = array_search($class, $relationObj->has_many());
|
||||
if ($manyField && strlen($relationName) > 0) {
|
||||
$manyField = $relationName;
|
||||
}
|
||||
}
|
||||
if (empty($manyField) && $relationObj->has_one()) {
|
||||
$oneField = array_search($class, $relationObj->has_one());
|
||||
if ($oneField && strlen($relationName) > 0) {
|
||||
$oneField = $relationName;
|
||||
}
|
||||
}
|
||||
if (empty($manyField) && empty($oneField)) {
|
||||
throw new \Exception("'$relationClass' has no relationship (has_one, has_many and many_many) with '$class'!");
|
||||
}
|
||||
|
||||
// Get the searchable field to check if the fixture object already exists
|
||||
$temObj = new $class;
|
||||
if(isset($temObj->Name)) $field = "Name";
|
||||
else if(isset($temObj->Title)) $field = "Title";
|
||||
else $field = "ID";
|
||||
// Get the searchable field to check if the fixture object already exists
|
||||
$temObj = new $class;
|
||||
if (isset($temObj->Name)) {
|
||||
$field = "Name";
|
||||
} elseif (isset($temObj->Title)) {
|
||||
$field = "Title";
|
||||
} else {
|
||||
$field = "ID";
|
||||
}
|
||||
|
||||
// Check if the fixture object exists - if not, we create it
|
||||
$obj = DataObject::get($class)->filter($field, $value)->first();
|
||||
if(!$obj) $obj = $this->fixtureFactory->createObject($class, $value);
|
||||
// If has_many or many_many, add this fixture object to the relation object
|
||||
// If has_one, set value to the joint field with this fixture object's ID
|
||||
if($manyField) {
|
||||
$relationObj->$manyField()->add($obj);
|
||||
} else if($oneField) {
|
||||
// E.g. $has_one = array('PanelOffer' => 'Offer');
|
||||
// then the join field is PanelOfferID. This is the common rule in the CMS
|
||||
$relationObj->{$oneField . 'ID'} = $obj->ID;
|
||||
}
|
||||
// Check if the fixture object exists - if not, we create it
|
||||
$obj = DataObject::get($class)->filter($field, $value)->first();
|
||||
if (!$obj) {
|
||||
$obj = $this->fixtureFactory->createObject($class, $value);
|
||||
}
|
||||
// If has_many or many_many, add this fixture object to the relation object
|
||||
// If has_one, set value to the joint field with this fixture object's ID
|
||||
if ($manyField) {
|
||||
$relationObj->$manyField()->add($obj);
|
||||
} elseif ($oneField) {
|
||||
// E.g. $has_one = array('PanelOffer' => 'Offer');
|
||||
// then the join field is PanelOfferID. This is the common rule in the CMS
|
||||
$relationObj->{$oneField . 'ID'} = $obj->ID;
|
||||
}
|
||||
|
||||
$relationObj->write();
|
||||
}
|
||||
$relationObj->write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given the "page" "Page 1" is not published
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" is (?<state>[^"]*)$/
|
||||
*/
|
||||
public function stepUpdateRecordState($type, $id, $state) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
/**
|
||||
* Example: Given the "page" "Page 1" is not published
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" is (?<state>[^"]*)$/
|
||||
*/
|
||||
public function stepUpdateRecordState($type, $id, $state)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
/** @var DataObject|Versioned $obj */
|
||||
$obj = $this->fixtureFactory->get($class, $id);
|
||||
if(!$obj) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Can not find record "%s" with identifier "%s"',
|
||||
$type,
|
||||
$id
|
||||
));
|
||||
}
|
||||
if (!$obj) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Can not find record "%s" with identifier "%s"',
|
||||
$type,
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
switch($state) {
|
||||
case 'published':
|
||||
$obj->copyVersionToStage('Stage', 'Live');
|
||||
break;
|
||||
case 'not published':
|
||||
case 'unpublished':
|
||||
$oldMode = Versioned::get_reading_mode();
|
||||
Versioned::set_stage(Versioned::LIVE);
|
||||
$clone = clone $obj;
|
||||
$clone->delete();
|
||||
Versioned::set_reading_mode($oldMode);
|
||||
break;
|
||||
case 'deleted':
|
||||
$obj->delete();
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid state: "%s"', $state
|
||||
));
|
||||
}
|
||||
}
|
||||
switch ($state) {
|
||||
case 'published':
|
||||
$obj->copyVersionToStage('Stage', 'Live');
|
||||
break;
|
||||
case 'not published':
|
||||
case 'unpublished':
|
||||
$oldMode = Versioned::get_reading_mode();
|
||||
Versioned::set_stage(Versioned::LIVE);
|
||||
$clone = clone $obj;
|
||||
$clone->delete();
|
||||
Versioned::set_reading_mode($oldMode);
|
||||
break;
|
||||
case 'deleted':
|
||||
$obj->delete();
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid state: "%s"',
|
||||
$state
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts YAML fixture definitions similar to the ones used in SilverStripe unit testing.
|
||||
*
|
||||
* Example: Given there are the following member records:
|
||||
* member1:
|
||||
* Email: member1@test.com
|
||||
* member2:
|
||||
* Email: member2@test.com
|
||||
*
|
||||
* @Given /^there are the following ([^\s]*) records$/
|
||||
*/
|
||||
public function stepThereAreTheFollowingRecords($dataObject, PyStringNode $string) {
|
||||
$yaml = array_merge(array($dataObject . ':'), $string->getLines());
|
||||
$yaml = implode("\n ", $yaml);
|
||||
/**
|
||||
* Accepts YAML fixture definitions similar to the ones used in SilverStripe unit testing.
|
||||
*
|
||||
* Example: Given there are the following member records:
|
||||
* member1:
|
||||
* Email: member1@test.com
|
||||
* member2:
|
||||
* Email: member2@test.com
|
||||
*
|
||||
* @Given /^there are the following ([^\s]*) records$/
|
||||
*/
|
||||
public function stepThereAreTheFollowingRecords($dataObject, PyStringNode $string)
|
||||
{
|
||||
$yaml = array_merge(array($dataObject . ':'), $string->getLines());
|
||||
$yaml = implode("\n ", $yaml);
|
||||
|
||||
// Save fixtures into database
|
||||
// TODO Run prepareAsset() for each File and Folder record
|
||||
$yamlFixture = new \YamlFixture($yaml);
|
||||
$yamlFixture->writeInto($this->getFixtureFactory());
|
||||
}
|
||||
// Save fixtures into database
|
||||
// TODO Run prepareAsset() for each File and Folder record
|
||||
$yamlFixture = new \YamlFixture($yaml);
|
||||
$yamlFixture->writeInto($this->getFixtureFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a "member" "Admin" belonging to "Admin Group"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"member" "(?<id>[^"]+)" belonging to "(?<groupId>[^"]+)"$/
|
||||
*/
|
||||
public function stepCreateMemberWithGroup($id, $groupId) {
|
||||
$group = $this->fixtureFactory->get('SilverStripe\\Security\\Group', $groupId);
|
||||
if(!$group) $group = $this->fixtureFactory->createObject('SilverStripe\\Security\\Group', $groupId);
|
||||
/**
|
||||
* Example: Given a "member" "Admin" belonging to "Admin Group"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"member" "(?<id>[^"]+)" belonging to "(?<groupId>[^"]+)"$/
|
||||
*/
|
||||
public function stepCreateMemberWithGroup($id, $groupId)
|
||||
{
|
||||
$group = $this->fixtureFactory->get('SilverStripe\\Security\\Group', $groupId);
|
||||
if (!$group) {
|
||||
$group = $this->fixtureFactory->createObject('SilverStripe\\Security\\Group', $groupId);
|
||||
}
|
||||
|
||||
$member = $this->fixtureFactory->createObject('SilverStripe\\Security\\Member', $id);
|
||||
$member->Groups()->add($group);
|
||||
}
|
||||
$member = $this->fixtureFactory->createObject('SilverStripe\\Security\\Member', $id);
|
||||
$member->Groups()->add($group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a "member" "Admin" belonging to "Admin Group" with "Email"="test@test.com"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"member" "(?<id>[^"]+)" belonging to "(?<groupId>[^"]+)" with (?<data>.*)$/
|
||||
*/
|
||||
public function stepCreateMemberWithGroupAndData($id, $groupId, $data) {
|
||||
$class = 'SilverStripe\\Security\\Member';
|
||||
preg_match_all(
|
||||
'/"(?<key>[^"]+)"\s*=\s*"(?<value>[^"]+)"/',
|
||||
$data,
|
||||
$matches
|
||||
);
|
||||
$fields = $this->convertFields(
|
||||
$class,
|
||||
array_combine($matches['key'], $matches['value'])
|
||||
);
|
||||
/**
|
||||
* Example: Given a "member" "Admin" belonging to "Admin Group" with "Email"="test@test.com"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"member" "(?<id>[^"]+)" belonging to "(?<groupId>[^"]+)" with (?<data>.*)$/
|
||||
*/
|
||||
public function stepCreateMemberWithGroupAndData($id, $groupId, $data)
|
||||
{
|
||||
$class = 'SilverStripe\\Security\\Member';
|
||||
preg_match_all(
|
||||
'/"(?<key>[^"]+)"\s*=\s*"(?<value>[^"]+)"/',
|
||||
$data,
|
||||
$matches
|
||||
);
|
||||
$fields = $this->convertFields(
|
||||
$class,
|
||||
array_combine($matches['key'], $matches['value'])
|
||||
);
|
||||
|
||||
$group = $this->fixtureFactory->get('SilverStripe\\Security\\Group', $groupId);
|
||||
if(!$group) $group = $this->fixtureFactory->createObject('SilverStripe\\Security\\Group', $groupId);
|
||||
$group = $this->fixtureFactory->get('SilverStripe\\Security\\Group', $groupId);
|
||||
if (!$group) {
|
||||
$group = $this->fixtureFactory->createObject('SilverStripe\\Security\\Group', $groupId);
|
||||
}
|
||||
|
||||
$member = $this->fixtureFactory->createObject($class, $id, $fields);
|
||||
$member->Groups()->add($group);
|
||||
}
|
||||
$member = $this->fixtureFactory->createObject($class, $id, $fields);
|
||||
$member->Groups()->add($group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a "group" "Admin" with permissions "Access to 'Pages' section" and "Access to 'Files' section"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"group" "(?<id>[^"]+)" (?:(with|has)) permissions (?<permissionStr>.*)$/
|
||||
*/
|
||||
public function stepCreateGroupWithPermissions($id, $permissionStr) {
|
||||
// Convert natural language permissions to codes
|
||||
preg_match_all('/"([^"]+)"/', $permissionStr, $matches);
|
||||
$permissions = $matches[1];
|
||||
$codes = Permission::get_codes(false);
|
||||
/**
|
||||
* Example: Given a "group" "Admin" with permissions "Access to 'Pages' section" and "Access to 'Files' section"
|
||||
*
|
||||
* @Given /^(?:(an|a|the) )"group" "(?<id>[^"]+)" (?:(with|has)) permissions (?<permissionStr>.*)$/
|
||||
*/
|
||||
public function stepCreateGroupWithPermissions($id, $permissionStr)
|
||||
{
|
||||
// Convert natural language permissions to codes
|
||||
preg_match_all('/"([^"]+)"/', $permissionStr, $matches);
|
||||
$permissions = $matches[1];
|
||||
$codes = Permission::get_codes(false);
|
||||
|
||||
$group = $this->fixtureFactory->get('SilverStripe\\Security\\Group', $id);
|
||||
if(!$group) $group = $this->fixtureFactory->createObject('SilverStripe\\Security\\Group', $id);
|
||||
$group = $this->fixtureFactory->get('SilverStripe\\Security\\Group', $id);
|
||||
if (!$group) {
|
||||
$group = $this->fixtureFactory->createObject('SilverStripe\\Security\\Group', $id);
|
||||
}
|
||||
|
||||
foreach($permissions as $permission) {
|
||||
$found = false;
|
||||
foreach($codes as $code => $details) {
|
||||
if(
|
||||
$permission == $code
|
||||
|| $permission == $details['name']
|
||||
) {
|
||||
Permission::grant($group->ID, $code);
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
if(!$found) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'No permission found for "%s"', $permission
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($permissions as $permission) {
|
||||
$found = false;
|
||||
foreach ($codes as $code => $details) {
|
||||
if ($permission == $code
|
||||
|| $permission == $details['name']
|
||||
) {
|
||||
Permission::grant($group->ID, $code);
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'No permission found for "%s"',
|
||||
$permission
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a record based on its identifier set during fixture creation,
|
||||
* using its RelativeLink() method to map the record to a URL.
|
||||
* Example: Given I go to the "page" "My Page"
|
||||
*
|
||||
* @Given /^I go to (?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)"/
|
||||
*/
|
||||
public function stepGoToNamedRecord($type, $id) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$record = $this->fixtureFactory->get($class, $id);
|
||||
if(!$record) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Cannot resolve reference "%s", no matching fixture found',
|
||||
$id
|
||||
));
|
||||
}
|
||||
if(!$record->hasMethod('RelativeLink')) {
|
||||
throw new \InvalidArgumentException('URL for record cannot be determined, missing RelativeLink() method');
|
||||
}
|
||||
/**
|
||||
* Navigates to a record based on its identifier set during fixture creation,
|
||||
* using its RelativeLink() method to map the record to a URL.
|
||||
* Example: Given I go to the "page" "My Page"
|
||||
*
|
||||
* @Given /^I go to (?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)"/
|
||||
*/
|
||||
public function stepGoToNamedRecord($type, $id)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$record = $this->fixtureFactory->get($class, $id);
|
||||
if (!$record) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Cannot resolve reference "%s", no matching fixture found',
|
||||
$id
|
||||
));
|
||||
}
|
||||
if (!$record->hasMethod('RelativeLink')) {
|
||||
throw new \InvalidArgumentException('URL for record cannot be determined, missing RelativeLink() method');
|
||||
}
|
||||
|
||||
$this->getSession()->visit($this->getMainContext()->locatePath($record->RelativeLink()));
|
||||
}
|
||||
$this->getSession()->visit($this->getMainContext()->locatePath($record->RelativeLink()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that a file or folder exists in the webroot.
|
||||
* Example: There should be a file "assets/Uploads/test.jpg"
|
||||
*
|
||||
* @Then /^there should be a (?<type>(file|folder) )"(?<path>[^"]*)"/
|
||||
*/
|
||||
public function stepThereShouldBeAFileOrFolder($type, $path) {
|
||||
assertFileExists($this->joinPaths(BASE_PATH, $path));
|
||||
}
|
||||
/**
|
||||
* Checks that a file or folder exists in the webroot.
|
||||
* Example: There should be a file "assets/Uploads/test.jpg"
|
||||
*
|
||||
* @Then /^there should be a (?<type>(file|folder) )"(?<path>[^"]*)"/
|
||||
*/
|
||||
public function stepThereShouldBeAFileOrFolder($type, $path)
|
||||
{
|
||||
assertFileExists($this->joinPaths(BASE_PATH, $path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a file exists in the asset store with a given filename and hash
|
||||
*
|
||||
* Example: there should be a filename "Uploads/test.jpg" with hash "59de0c841f"
|
||||
*
|
||||
* @Then /^there should be a filename "(?<filename>[^"]*)" with hash "(?<hash>[a-fA-Z0-9]+)"/
|
||||
*/
|
||||
public function stepThereShouldBeAFileWithTuple($filename, $hash) {
|
||||
$exists = $this->getAssetStore()->exists($filename, $hash);
|
||||
assertTrue((bool)$exists, "A file exists with filename $filename and hash $hash");
|
||||
}
|
||||
/**
|
||||
* Checks that a file exists in the asset store with a given filename and hash
|
||||
*
|
||||
* Example: there should be a filename "Uploads/test.jpg" with hash "59de0c841f"
|
||||
*
|
||||
* @Then /^there should be a filename "(?<filename>[^"]*)" with hash "(?<hash>[a-fA-Z0-9]+)"/
|
||||
*/
|
||||
public function stepThereShouldBeAFileWithTuple($filename, $hash)
|
||||
{
|
||||
$exists = $this->getAssetStore()->exists($filename, $hash);
|
||||
assertTrue((bool)$exists, "A file exists with filename $filename and hash $hash");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces fixture references in values with their respective database IDs,
|
||||
* with the notation "=><class>.<identifier>". Example: "=>Page.My Page".
|
||||
*
|
||||
* @Transform /^([^"]+)$/
|
||||
*/
|
||||
public function lookupFixtureReference($string) {
|
||||
if(preg_match('/^=>/', $string)) {
|
||||
list($className, $identifier) = explode('.', preg_replace('/^=>/', '', $string), 2);
|
||||
$id = $this->fixtureFactory->getId($className, $identifier);
|
||||
if(!$id) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Cannot resolve reference "%s", no matching fixture found',
|
||||
$string
|
||||
));
|
||||
}
|
||||
return $id;
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replaces fixture references in values with their respective database IDs,
|
||||
* with the notation "=><class>.<identifier>". Example: "=>Page.My Page".
|
||||
*
|
||||
* @Transform /^([^"]+)$/
|
||||
*/
|
||||
public function lookupFixtureReference($string)
|
||||
{
|
||||
if (preg_match('/^=>/', $string)) {
|
||||
list($className, $identifier) = explode('.', preg_replace('/^=>/', '', $string), 2);
|
||||
$id = $this->fixtureFactory->getId($className, $identifier);
|
||||
if (!$id) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Cannot resolve reference "%s", no matching fixture found',
|
||||
$string
|
||||
));
|
||||
}
|
||||
return $id;
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]*)" "(?<id>[^"]*)" was (?<mod>(created|last edited)) "(?<time>[^"]*)"$/
|
||||
*/
|
||||
public function aRecordWasLastEditedRelative($type, $id, $mod, $time) {
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$fields = $this->prepareFixture($class, $id);
|
||||
$record = $this->fixtureFactory->createObject($class, $id, $fields);
|
||||
$date = date("Y-m-d H:i:s",strtotime($time));
|
||||
$table = $record->baseTable();
|
||||
$field = ($mod == 'created') ? 'Created' : 'LastEdited';
|
||||
DB::prepared_query(
|
||||
/**
|
||||
* @Given /^(?:(an|a|the) )"(?<type>[^"]*)" "(?<id>[^"]*)" was (?<mod>(created|last edited)) "(?<time>[^"]*)"$/
|
||||
*/
|
||||
public function aRecordWasLastEditedRelative($type, $id, $mod, $time)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$fields = $this->prepareFixture($class, $id);
|
||||
$record = $this->fixtureFactory->createObject($class, $id, $fields);
|
||||
$date = date("Y-m-d H:i:s", strtotime($time));
|
||||
$table = $record->baseTable();
|
||||
$field = ($mod == 'created') ? 'Created' : 'LastEdited';
|
||||
DB::prepared_query(
|
||||
"UPDATE \"{$table}\" SET \"{$field}\" = ? WHERE \"ID\" = ?",
|
||||
[$date, $record->ID]
|
||||
);
|
||||
// Support for Versioned extension, by checking for a "Live" stage
|
||||
if(DB::get_schema()->hasTable($table . '_Live')) {
|
||||
DB::prepared_query(
|
||||
"UPDATE \"{$table}_Live\" SET \"{$field}\" = ? WHERE \"ID\" = ?",
|
||||
[$date, $record->ID]
|
||||
);
|
||||
}
|
||||
}
|
||||
// Support for Versioned extension, by checking for a "Live" stage
|
||||
if (DB::get_schema()->hasTable($table . '_Live')) {
|
||||
DB::prepared_query(
|
||||
"UPDATE \"{$table}_Live\" SET \"{$field}\" = ? WHERE \"ID\" = ?",
|
||||
[$date, $record->ID]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a fixture for use
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $identifier
|
||||
* @param array $data
|
||||
* @return array Prepared $data with additional injected fields
|
||||
*/
|
||||
protected function prepareFixture($class, $identifier, $data = array()) {
|
||||
if($class == 'File' || is_subclass_of($class, 'File')) {
|
||||
$data = $this->prepareAsset($class, $identifier, $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* Prepares a fixture for use
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $identifier
|
||||
* @param array $data
|
||||
* @return array Prepared $data with additional injected fields
|
||||
*/
|
||||
protected function prepareFixture($class, $identifier, $data = array())
|
||||
{
|
||||
if ($class == 'File' || is_subclass_of($class, 'File')) {
|
||||
$data = $this->prepareAsset($class, $identifier, $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function prepareAsset($class, $identifier, $data = null) {
|
||||
if(!$data) $data = array();
|
||||
$relativeTargetPath = (isset($data['Filename'])) ? $data['Filename'] : $identifier;
|
||||
$relativeTargetPath = preg_replace('/^' . ASSETS_DIR . '\/?/', '', $relativeTargetPath);
|
||||
$sourcePath = $this->joinPaths($this->getFilesPath(), basename($relativeTargetPath));
|
||||
protected function prepareAsset($class, $identifier, $data = null)
|
||||
{
|
||||
if (!$data) {
|
||||
$data = array();
|
||||
}
|
||||
$relativeTargetPath = (isset($data['Filename'])) ? $data['Filename'] : $identifier;
|
||||
$relativeTargetPath = preg_replace('/^' . ASSETS_DIR . '\/?/', '', $relativeTargetPath);
|
||||
$sourcePath = $this->joinPaths($this->getFilesPath(), basename($relativeTargetPath));
|
||||
|
||||
// Create file or folder on filesystem
|
||||
if($class == 'Folder' || is_subclass_of($class, 'Folder')) {
|
||||
$parent = \Folder::find_or_make($relativeTargetPath);
|
||||
$data['ID'] = $parent->ID;
|
||||
} else {
|
||||
$parent = \Folder::find_or_make(dirname($relativeTargetPath));
|
||||
if(!file_exists($sourcePath)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Source file for "%s" cannot be found in "%s"',
|
||||
$relativeTargetPath,
|
||||
$sourcePath
|
||||
));
|
||||
}
|
||||
$data['ParentID'] = $parent->ID;
|
||||
// Create file or folder on filesystem
|
||||
if ($class == 'Folder' || is_subclass_of($class, 'Folder')) {
|
||||
$parent = \Folder::find_or_make($relativeTargetPath);
|
||||
$data['ID'] = $parent->ID;
|
||||
} else {
|
||||
$parent = \Folder::find_or_make(dirname($relativeTargetPath));
|
||||
if (!file_exists($sourcePath)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Source file for "%s" cannot be found in "%s"',
|
||||
$relativeTargetPath,
|
||||
$sourcePath
|
||||
));
|
||||
}
|
||||
$data['ParentID'] = $parent->ID;
|
||||
|
||||
// Load file into APL and retrieve tuple
|
||||
$asset = $this->getAssetStore()->setFromLocalFile(
|
||||
$sourcePath,
|
||||
$relativeTargetPath,
|
||||
null,
|
||||
null,
|
||||
array(
|
||||
'conflict' => AssetStore::CONFLICT_OVERWRITE,
|
||||
'visibility' => AssetStore::VISIBILITY_PUBLIC
|
||||
)
|
||||
);
|
||||
$data['FileFilename'] = $asset['Filename'];
|
||||
$data['FileHash'] = $asset['Hash'];
|
||||
$data['FileVariant'] = $asset['Variant'];
|
||||
}
|
||||
if(!isset($data['Name'])) {
|
||||
$data['Name'] = basename($relativeTargetPath);
|
||||
}
|
||||
// Load file into APL and retrieve tuple
|
||||
$asset = $this->getAssetStore()->setFromLocalFile(
|
||||
$sourcePath,
|
||||
$relativeTargetPath,
|
||||
null,
|
||||
null,
|
||||
array(
|
||||
'conflict' => AssetStore::CONFLICT_OVERWRITE,
|
||||
'visibility' => AssetStore::VISIBILITY_PUBLIC
|
||||
)
|
||||
);
|
||||
$data['FileFilename'] = $asset['Filename'];
|
||||
$data['FileHash'] = $asset['Hash'];
|
||||
$data['FileVariant'] = $asset['Variant'];
|
||||
}
|
||||
if (!isset($data['Name'])) {
|
||||
$data['Name'] = basename($relativeTargetPath);
|
||||
}
|
||||
|
||||
// Save assets
|
||||
if(isset($data['FileFilename'])) {
|
||||
$this->createdAssets[] = $data;
|
||||
}
|
||||
// Save assets
|
||||
if (isset($data['FileFilename'])) {
|
||||
$this->createdAssets[] = $data;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return AssetStore
|
||||
*/
|
||||
protected function getAssetStore() {
|
||||
return singleton('AssetStore');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return AssetStore
|
||||
*/
|
||||
protected function getAssetStore()
|
||||
{
|
||||
return singleton('AssetStore');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a natural language class description to an actual class name.
|
||||
* Respects {@link DataObject::$singular_name} variations.
|
||||
* Example: "redirector page" -> "RedirectorPage"
|
||||
*
|
||||
* @param String
|
||||
* @return String Class name
|
||||
*/
|
||||
protected function convertTypeToClass($type) {
|
||||
$type = trim($type);
|
||||
/**
|
||||
* Converts a natural language class description to an actual class name.
|
||||
* Respects {@link DataObject::$singular_name} variations.
|
||||
* Example: "redirector page" -> "RedirectorPage"
|
||||
*
|
||||
* @param String
|
||||
* @return String Class name
|
||||
*/
|
||||
protected function convertTypeToClass($type)
|
||||
{
|
||||
$type = trim($type);
|
||||
|
||||
// Try direct mapping
|
||||
$class = str_replace(' ', '', ucwords($type));
|
||||
if(class_exists($class) && is_subclass_of($class, 'SilverStripe\\ORM\\DataObject')) {
|
||||
return \ClassInfo::class_name($class);
|
||||
}
|
||||
// Try direct mapping
|
||||
$class = str_replace(' ', '', ucwords($type));
|
||||
if (class_exists($class) && is_subclass_of($class, 'SilverStripe\\ORM\\DataObject')) {
|
||||
return \ClassInfo::class_name($class);
|
||||
}
|
||||
|
||||
// Fall back to singular names
|
||||
foreach(array_values(\ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject')) as $candidate) {
|
||||
if(strcasecmp(singleton($candidate)->singular_name(), $type) === 0) {
|
||||
// Fall back to singular names
|
||||
foreach (array_values(\ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject')) as $candidate) {
|
||||
if (strcasecmp(singleton($candidate)->singular_name(), $type) === 0) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Class "%s" does not exist, or is not a subclass of DataObjet',
|
||||
$class
|
||||
));
|
||||
}
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Class "%s" does not exist, or is not a subclass of DataObjet',
|
||||
$class
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an object with values, resolving aliases set through
|
||||
* {@link DataObject->fieldLabels()}.
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param array $fields Map of field names or aliases to their values.
|
||||
* @return array Map of actual object properties to their values.
|
||||
*/
|
||||
protected function convertFields($class, $fields) {
|
||||
$labels = singleton($class)->fieldLabels();
|
||||
foreach($fields as $fieldName => $fieldVal) {
|
||||
if($fieldLabelKey = array_search($fieldName, $labels)) {
|
||||
unset($fields[$fieldName]);
|
||||
$fields[$labels[$fieldLabelKey]] = $fieldVal;
|
||||
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function joinPaths() {
|
||||
$args = func_get_args();
|
||||
$paths = array();
|
||||
foreach($args as $arg) $paths = array_merge($paths, (array)$arg);
|
||||
foreach($paths as &$path) $path = trim($path, '/');
|
||||
if (substr($args[0], 0, 1) == '/') $paths[0] = '/' . $paths[0];
|
||||
return join('/', $paths);
|
||||
}
|
||||
/**
|
||||
* Updates an object with values, resolving aliases set through
|
||||
* {@link DataObject->fieldLabels()}.
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param array $fields Map of field names or aliases to their values.
|
||||
* @return array Map of actual object properties to their values.
|
||||
*/
|
||||
protected function convertFields($class, $fields)
|
||||
{
|
||||
$labels = singleton($class)->fieldLabels();
|
||||
foreach ($fields as $fieldName => $fieldVal) {
|
||||
if ($fieldLabelKey = array_search($fieldName, $labels)) {
|
||||
unset($fields[$fieldName]);
|
||||
$fields[$labels[$fieldLabelKey]] = $fieldVal;
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function joinPaths()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$paths = array();
|
||||
foreach ($args as $arg) {
|
||||
$paths = array_merge($paths, (array)$arg);
|
||||
}
|
||||
foreach ($paths as &$path) {
|
||||
$path = trim($path, '/');
|
||||
}
|
||||
if (substr($args[0], 0, 1) == '/') {
|
||||
$paths[0] = '/' . $paths[0];
|
||||
}
|
||||
return join('/', $paths);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Context\Initializer;
|
||||
|
||||
use Behat\Behat\Context\Initializer\InitializerInterface,
|
||||
Behat\Behat\Context\ContextInterface;
|
||||
use Behat\Behat\Context\Initializer\InitializerInterface;
|
||||
use Behat\Behat\Context\ContextInterface;
|
||||
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeAwareContextInterface;
|
||||
|
||||
@ -52,10 +52,10 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
*/
|
||||
protected $screenshotPath;
|
||||
|
||||
/**
|
||||
* @var object {@link TestSessionEnvironment}
|
||||
*/
|
||||
protected $testSessionEnvironment;
|
||||
/**
|
||||
* @var object {@link TestSessionEnvironment}
|
||||
*/
|
||||
protected $testSessionEnvironment;
|
||||
|
||||
/**
|
||||
* Initializes initializer.
|
||||
@ -64,19 +64,19 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
{
|
||||
$this->bootstrap($frameworkPath);
|
||||
|
||||
file_put_contents('php://stdout', "Creating test session environment" . PHP_EOL);
|
||||
file_put_contents('php://stdout', "Creating test session environment" . PHP_EOL);
|
||||
|
||||
$testEnv = \Injector::inst()->get('TestSessionEnvironment');
|
||||
$testEnv->startTestSession(array(
|
||||
'createDatabase' => true
|
||||
));
|
||||
$testEnv = \Injector::inst()->get('TestSessionEnvironment');
|
||||
$testEnv->startTestSession(array(
|
||||
'createDatabase' => true
|
||||
));
|
||||
|
||||
$state = $testEnv->getState();
|
||||
$state = $testEnv->getState();
|
||||
|
||||
$this->databaseName = $state->database;
|
||||
$this->testSessionEnvironment = $testEnv;
|
||||
$this->databaseName = $state->database;
|
||||
$this->testSessionEnvironment = $testEnv;
|
||||
|
||||
file_put_contents('php://stdout', "Temp Database: $this->databaseName" . PHP_EOL . PHP_EOL);
|
||||
file_put_contents('php://stdout', "Temp Database: $this->databaseName" . PHP_EOL . PHP_EOL);
|
||||
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
}
|
||||
@ -84,7 +84,7 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
public function __destruct()
|
||||
{
|
||||
// Add condition here as register_shutdown_function() also calls this in __construct()
|
||||
if($this->testSessionEnvironment) {
|
||||
if ($this->testSessionEnvironment) {
|
||||
file_put_contents('php://stdout', "Killing test session environment...");
|
||||
$this->testSessionEnvironment->endTestSession();
|
||||
$this->testSessionEnvironment = null;
|
||||
@ -122,7 +122,9 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
|
||||
public function setAjaxSteps($ajaxSteps)
|
||||
{
|
||||
if($ajaxSteps) $this->ajaxSteps = $ajaxSteps;
|
||||
if ($ajaxSteps) {
|
||||
$this->ajaxSteps = $ajaxSteps;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAjaxSteps()
|
||||
@ -170,11 +172,13 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
|
||||
public function getRegionMap(){
|
||||
public function getRegionMap()
|
||||
{
|
||||
return $this->regionMap;
|
||||
}
|
||||
|
||||
public function setRegionMap($regionMap) {
|
||||
public function setRegionMap($regionMap)
|
||||
{
|
||||
$this->regionMap = $regionMap;
|
||||
}
|
||||
|
||||
@ -193,4 +197,4 @@ class SilverStripeAwareInitializer implements InitializerInterface
|
||||
// Remove the error handler so that PHPUnit can add its own
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Security\Group;
|
||||
use SilverStripe\Security\Member;
|
||||
|
||||
|
||||
|
||||
// PHPUnit
|
||||
require_once BASE_PATH . '/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php';
|
||||
|
||||
@ -70,7 +68,7 @@ class LoginContext extends BehatContext
|
||||
*
|
||||
* @Given /^I am logged in with "([^"]*)" permissions$/
|
||||
*/
|
||||
function iAmLoggedInWithPermissions($permCode)
|
||||
public function iAmLoggedInWithPermissions($permCode)
|
||||
{
|
||||
if (!isset($this->cache_generatedMembers[$permCode])) {
|
||||
$group = Group::get()->filter('Title', "$permCode group")->first();
|
||||
@ -132,8 +130,8 @@ class LoginContext extends BehatContext
|
||||
|
||||
// Try to find visible forms again on login page.
|
||||
$visibleForm = null;
|
||||
foreach($forms as $form) {
|
||||
if($form->isVisible() && $form->find('css', '[name=Email]')) {
|
||||
foreach ($forms as $form) {
|
||||
if ($form->isVisible() && $form->find('css', '[name=Email]')) {
|
||||
$visibleForm = $form;
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ interface SilverStripeAwareContextInterface
|
||||
|
||||
/**
|
||||
* Marks steps as AJAX steps for special treatment
|
||||
*
|
||||
*
|
||||
* @param array $ajax_steps Array of step name parts to match
|
||||
*/
|
||||
public function setAjaxSteps($ajaxSteps);
|
||||
public function setAjaxSteps($ajaxSteps);
|
||||
}
|
||||
|
@ -2,16 +2,16 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension\Context;
|
||||
|
||||
use Behat\Behat\Context\Step,
|
||||
Behat\Behat\Event\FeatureEvent,
|
||||
Behat\Behat\Event\ScenarioEvent,
|
||||
Behat\Behat\Event\SuiteEvent;
|
||||
use Behat\Behat\Context\Step;
|
||||
use Behat\Behat\Event\FeatureEvent;
|
||||
use Behat\Behat\Event\ScenarioEvent;
|
||||
use Behat\Behat\Event\SuiteEvent;
|
||||
use Behat\Gherkin\Node\PyStringNode;
|
||||
use Behat\MinkExtension\Context\MinkContext;
|
||||
use Behat\Mink\Driver\GoutteDriver,
|
||||
Behat\Mink\Driver\Selenium2Driver,
|
||||
Behat\Mink\Exception\UnsupportedDriverActionException,
|
||||
Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Behat\Mink\Driver\GoutteDriver;
|
||||
use Behat\Mink\Driver\Selenium2Driver;
|
||||
use Behat\Mink\Exception\UnsupportedDriverActionException;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeAwareContextInterface;
|
||||
|
||||
@ -29,466 +29,508 @@ require_once BASE_PATH . '/vendor/phpunit/phpunit/src/Framework/Assert/Functions
|
||||
*/
|
||||
class SilverStripeContext extends MinkContext implements SilverStripeAwareContextInterface
|
||||
{
|
||||
protected $databaseName;
|
||||
protected $databaseName;
|
||||
|
||||
/**
|
||||
* @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 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 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 admin interface.
|
||||
*/
|
||||
protected $adminUrl;
|
||||
|
||||
/**
|
||||
* @var String Relative URL to the SilverStripe login form.
|
||||
*/
|
||||
protected $loginUrl;
|
||||
/**
|
||||
* @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;
|
||||
/**
|
||||
* @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 $context;
|
||||
|
||||
protected $testSessionEnvironment;
|
||||
protected $testSessionEnvironment;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters) {
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
$this->testSessionEnvironment = new \TestSessionEnvironment();
|
||||
}
|
||||
/**
|
||||
* Initializes context.
|
||||
* Every scenario gets it's own context object.
|
||||
*
|
||||
* @param array $parameters context parameters (set them up through behat.yml)
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
// Initialize your context here
|
||||
$this->context = $parameters;
|
||||
$this->testSessionEnvironment = new \TestSessionEnvironment();
|
||||
}
|
||||
|
||||
public function setDatabase($databaseName) {
|
||||
$this->databaseName = $databaseName;
|
||||
}
|
||||
public function setDatabase($databaseName)
|
||||
{
|
||||
$this->databaseName = $databaseName;
|
||||
}
|
||||
|
||||
public function setAjaxSteps($ajaxSteps) {
|
||||
if($ajaxSteps) $this->ajaxSteps = $ajaxSteps;
|
||||
}
|
||||
public function setAjaxSteps($ajaxSteps)
|
||||
{
|
||||
if ($ajaxSteps) {
|
||||
$this->ajaxSteps = $ajaxSteps;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAjaxSteps() {
|
||||
return $this->ajaxSteps;
|
||||
}
|
||||
public function getAjaxSteps()
|
||||
{
|
||||
return $this->ajaxSteps;
|
||||
}
|
||||
|
||||
public function setAjaxTimeout($ajaxTimeout) {
|
||||
$this->ajaxTimeout = $ajaxTimeout;
|
||||
}
|
||||
public function setAjaxTimeout($ajaxTimeout)
|
||||
{
|
||||
$this->ajaxTimeout = $ajaxTimeout;
|
||||
}
|
||||
|
||||
public function getAjaxTimeout() {
|
||||
return $this->ajaxTimeout;
|
||||
}
|
||||
public function getAjaxTimeout()
|
||||
{
|
||||
return $this->ajaxTimeout;
|
||||
}
|
||||
|
||||
public function setAdminUrl($adminUrl) {
|
||||
$this->adminUrl = $adminUrl;
|
||||
}
|
||||
public function setAdminUrl($adminUrl)
|
||||
{
|
||||
$this->adminUrl = $adminUrl;
|
||||
}
|
||||
|
||||
public function getAdminUrl() {
|
||||
return $this->adminUrl;
|
||||
}
|
||||
public function getAdminUrl()
|
||||
{
|
||||
return $this->adminUrl;
|
||||
}
|
||||
|
||||
public function setLoginUrl($loginUrl) {
|
||||
$this->loginUrl = $loginUrl;
|
||||
}
|
||||
public function setLoginUrl($loginUrl)
|
||||
{
|
||||
$this->loginUrl = $loginUrl;
|
||||
}
|
||||
|
||||
public function getLoginUrl() {
|
||||
return $this->loginUrl;
|
||||
}
|
||||
public function getLoginUrl()
|
||||
{
|
||||
return $this->loginUrl;
|
||||
}
|
||||
|
||||
public function setScreenshotPath($screenshotPath) {
|
||||
$this->screenshotPath = $screenshotPath;
|
||||
}
|
||||
public function setScreenshotPath($screenshotPath)
|
||||
{
|
||||
$this->screenshotPath = $screenshotPath;
|
||||
}
|
||||
|
||||
public function getScreenshotPath() {
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
public function getScreenshotPath()
|
||||
{
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
|
||||
public function getRegionMap(){
|
||||
return $this->regionMap;
|
||||
}
|
||||
public function getRegionMap()
|
||||
{
|
||||
return $this->regionMap;
|
||||
}
|
||||
|
||||
public function setRegionMap($regionMap){
|
||||
$this->regionMap = $regionMap;
|
||||
}
|
||||
public function setRegionMap($regionMap)
|
||||
{
|
||||
$this->regionMap = $regionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns MinkElement based off region defined in .yml file.
|
||||
* Also supports direct CSS selectors and regions identified by a "data-title" attribute.
|
||||
* When using the "data-title" attribute, ensure not to include double quotes.
|
||||
*
|
||||
* @param String $region Region name or CSS selector
|
||||
* @return MinkElement|null
|
||||
*/
|
||||
public function getRegionObj($region) {
|
||||
// Try to find regions directly by CSS selector.
|
||||
try {
|
||||
$regionObj = $this->getSession()->getPage()->find(
|
||||
'css',
|
||||
// Escape CSS selector
|
||||
(false !== strpos($region, "'")) ? str_replace("'", "\'", $region) : $region
|
||||
);
|
||||
if($regionObj) {
|
||||
return $regionObj;
|
||||
}
|
||||
} catch(\Symfony\Component\CssSelector\Exception\SyntaxErrorException $e) {
|
||||
// fall through to next case
|
||||
}
|
||||
/**
|
||||
* Returns MinkElement based off region defined in .yml file.
|
||||
* Also supports direct CSS selectors and regions identified by a "data-title" attribute.
|
||||
* When using the "data-title" attribute, ensure not to include double quotes.
|
||||
*
|
||||
* @param String $region Region name or CSS selector
|
||||
* @return MinkElement|null
|
||||
*/
|
||||
public function getRegionObj($region)
|
||||
{
|
||||
// Try to find regions directly by CSS selector.
|
||||
try {
|
||||
$regionObj = $this->getSession()->getPage()->find(
|
||||
'css',
|
||||
// Escape CSS selector
|
||||
(false !== strpos($region, "'")) ? str_replace("'", "\'", $region) : $region
|
||||
);
|
||||
if ($regionObj) {
|
||||
return $regionObj;
|
||||
}
|
||||
} catch (\Symfony\Component\CssSelector\Exception\SyntaxErrorException $e) {
|
||||
// fall through to next case
|
||||
}
|
||||
|
||||
// Fall back to region identified by data-title.
|
||||
// Only apply if no double quotes exist in search string,
|
||||
// which would break the CSS selector.
|
||||
if(false === strpos($region, '"')) {
|
||||
$regionObj = $this->getSession()->getPage()->find(
|
||||
'css',
|
||||
'[data-title="' . $region . '"]'
|
||||
);
|
||||
if($regionObj) {
|
||||
return $regionObj;
|
||||
}
|
||||
}
|
||||
// Fall back to region identified by data-title.
|
||||
// Only apply if no double quotes exist in search string,
|
||||
// which would break the CSS selector.
|
||||
if (false === strpos($region, '"')) {
|
||||
$regionObj = $this->getSession()->getPage()->find(
|
||||
'css',
|
||||
'[data-title="' . $region . '"]'
|
||||
);
|
||||
if ($regionObj) {
|
||||
return $regionObj;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for named region
|
||||
if(!$this->regionMap) {
|
||||
throw new \LogicException("Cannot find 'region_map' in the behat.yml");
|
||||
}
|
||||
if(!array_key_exists($region, $this->regionMap)) {
|
||||
throw new \LogicException("Cannot find the specified region in the behat.yml");
|
||||
}
|
||||
$regionObj = $this->getSession()->getPage()->find('css', $region);
|
||||
if(!$regionObj) {
|
||||
throw new ElementNotFoundException("Cannot find the specified region on the page");
|
||||
}
|
||||
// Look for named region
|
||||
if (!$this->regionMap) {
|
||||
throw new \LogicException("Cannot find 'region_map' in the behat.yml");
|
||||
}
|
||||
if (!array_key_exists($region, $this->regionMap)) {
|
||||
throw new \LogicException("Cannot find the specified region in the behat.yml");
|
||||
}
|
||||
$regionObj = $this->getSession()->getPage()->find('css', $region);
|
||||
if (!$regionObj) {
|
||||
throw new ElementNotFoundException("Cannot find the specified region on the page");
|
||||
}
|
||||
|
||||
return $regionObj;
|
||||
}
|
||||
return $regionObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario
|
||||
*/
|
||||
public function before(ScenarioEvent $event) {
|
||||
if (!isset($this->databaseName)) {
|
||||
throw new \LogicException(
|
||||
'Context\'s $databaseName has to be set when implementing SilverStripeAwareContextInterface.'
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @BeforeScenario
|
||||
*/
|
||||
public function before(ScenarioEvent $event)
|
||||
{
|
||||
if (!isset($this->databaseName)) {
|
||||
throw new \LogicException(
|
||||
'Context\'s $databaseName has to be set when implementing SilverStripeAwareContextInterface.'
|
||||
);
|
||||
}
|
||||
|
||||
$state = $this->getTestSessionState();
|
||||
$this->testSessionEnvironment->startTestSession($state);
|
||||
$state = $this->getTestSessionState();
|
||||
$this->testSessionEnvironment->startTestSession($state);
|
||||
|
||||
// Optionally import database
|
||||
if(!empty($state['importDatabasePath'])) {
|
||||
$this->testSessionEnvironment->importDatabase(
|
||||
$state['importDatabasePath'],
|
||||
!empty($state['requireDefaultRecords']) ? $state['requireDefaultRecords'] : false
|
||||
);
|
||||
} else if(!empty($state['requireDefaultRecords']) && $state['requireDefaultRecords']) {
|
||||
$this->testSessionEnvironment->requireDefaultRecords();
|
||||
}
|
||||
// Optionally import database
|
||||
if (!empty($state['importDatabasePath'])) {
|
||||
$this->testSessionEnvironment->importDatabase(
|
||||
$state['importDatabasePath'],
|
||||
!empty($state['requireDefaultRecords']) ? $state['requireDefaultRecords'] : false
|
||||
);
|
||||
} elseif (!empty($state['requireDefaultRecords']) && $state['requireDefaultRecords']) {
|
||||
$this->testSessionEnvironment->requireDefaultRecords();
|
||||
}
|
||||
|
||||
// Fixtures
|
||||
$fixtureFile = (!empty($state['fixture'])) ? $state['fixture'] : null;
|
||||
if($fixtureFile) {
|
||||
$this->testSessionEnvironment->loadFixtureIntoDb($fixtureFile);
|
||||
}
|
||||
// Fixtures
|
||||
$fixtureFile = (!empty($state['fixture'])) ? $state['fixture'] : null;
|
||||
if ($fixtureFile) {
|
||||
$this->testSessionEnvironment->loadFixtureIntoDb($fixtureFile);
|
||||
}
|
||||
|
||||
if($screenSize = getenv('BEHAT_SCREEN_SIZE')) {
|
||||
list($screenWidth, $screenHeight) = explode('x', $screenSize);
|
||||
$this->getSession()->resizeWindow((int)$screenWidth, (int)$screenHeight);
|
||||
} else {
|
||||
$this->getSession()->resizeWindow(1024, 768);
|
||||
}
|
||||
}
|
||||
if ($screenSize = getenv('BEHAT_SCREEN_SIZE')) {
|
||||
list($screenWidth, $screenHeight) = explode('x', $screenSize);
|
||||
$this->getSession()->resizeWindow((int)$screenWidth, (int)$screenHeight);
|
||||
} else {
|
||||
$this->getSession()->resizeWindow(1024, 768);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a parameter map of state to set within the test session.
|
||||
* Takes TESTSESSION_PARAMS environment variable into account for run-specific configurations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTestSessionState() {
|
||||
$extraParams = array();
|
||||
parse_str(getenv('TESTSESSION_PARAMS'), $extraParams);
|
||||
return array_merge(
|
||||
array(
|
||||
'database' => $this->databaseName,
|
||||
'mailer' => 'SilverStripe\BehatExtension\Utility\TestMailer',
|
||||
),
|
||||
$extraParams
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Returns a parameter map of state to set within the test session.
|
||||
* Takes TESTSESSION_PARAMS environment variable into account for run-specific configurations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTestSessionState()
|
||||
{
|
||||
$extraParams = array();
|
||||
parse_str(getenv('TESTSESSION_PARAMS'), $extraParams);
|
||||
return array_merge(
|
||||
array(
|
||||
'database' => $this->databaseName,
|
||||
'mailer' => 'SilverStripe\BehatExtension\Utility\TestMailer',
|
||||
),
|
||||
$extraParams
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses given URL and returns its components
|
||||
*
|
||||
* @param $url
|
||||
* @return array|mixed Parsed URL
|
||||
*/
|
||||
public function parseUrl($url) {
|
||||
$url = parse_url($url);
|
||||
$url['vars'] = array();
|
||||
if (!isset($url['fragment'])) {
|
||||
$url['fragment'] = null;
|
||||
}
|
||||
if (isset($url['query'])) {
|
||||
parse_str($url['query'], $url['vars']);
|
||||
}
|
||||
/**
|
||||
* Parses given URL and returns its components
|
||||
*
|
||||
* @param $url
|
||||
* @return array|mixed Parsed URL
|
||||
*/
|
||||
public function parseUrl($url)
|
||||
{
|
||||
$url = parse_url($url);
|
||||
$url['vars'] = array();
|
||||
if (!isset($url['fragment'])) {
|
||||
$url['fragment'] = null;
|
||||
}
|
||||
if (isset($url['query'])) {
|
||||
parse_str($url['query'], $url['vars']);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current URL is close enough to the given URL.
|
||||
* Unless specified in $url, get vars will be ignored
|
||||
* Unless specified in $url, fragment identifiers will be ignored
|
||||
*
|
||||
* @param $url string URL to compare to current URL
|
||||
* @return boolean Returns true if the current URL is close enough to the given URL, false otherwise.
|
||||
*/
|
||||
public function isCurrentUrlSimilarTo($url) {
|
||||
$current = $this->parseUrl($this->getSession()->getCurrentUrl());
|
||||
$test = $this->parseUrl($url);
|
||||
/**
|
||||
* Checks whether current URL is close enough to the given URL.
|
||||
* Unless specified in $url, get vars will be ignored
|
||||
* Unless specified in $url, fragment identifiers will be ignored
|
||||
*
|
||||
* @param $url string URL to compare to current URL
|
||||
* @return boolean Returns true if the current URL is close enough to the given URL, false otherwise.
|
||||
*/
|
||||
public function isCurrentUrlSimilarTo($url)
|
||||
{
|
||||
$current = $this->parseUrl($this->getSession()->getCurrentUrl());
|
||||
$test = $this->parseUrl($url);
|
||||
|
||||
if ($current['path'] !== $test['path']) {
|
||||
return false;
|
||||
}
|
||||
if ($current['path'] !== $test['path']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($test['fragment']) && $current['fragment'] !== $test['fragment']) {
|
||||
return false;
|
||||
}
|
||||
if (isset($test['fragment']) && $current['fragment'] !== $test['fragment']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($test['vars'] as $name => $value) {
|
||||
if (!isset($current['vars'][$name]) || $current['vars'][$name] !== $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach ($test['vars'] as $name => $value) {
|
||||
if (!isset($current['vars'][$name]) || $current['vars'][$name] !== $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns base URL parameter set in MinkExtension.
|
||||
* It simplifies configuration by allowing to specify this parameter
|
||||
* once but makes code dependent on MinkExtension.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseUrl() {
|
||||
return $this->getMinkParameter('base_url') ?: '';
|
||||
}
|
||||
/**
|
||||
* Returns base URL parameter set in MinkExtension.
|
||||
* It simplifies configuration by allowing to specify this parameter
|
||||
* once but makes code dependent on MinkExtension.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseUrl()
|
||||
{
|
||||
return $this->getMinkParameter('base_url') ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins URL parts into an URL using forward slash.
|
||||
* Forward slash usages are normalised to one between parts.
|
||||
* This method takes variable number of parameters.
|
||||
*
|
||||
* @param $...
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function joinUrlParts() {
|
||||
if (0 === func_num_args()) {
|
||||
throw new \InvalidArgumentException('Need at least one argument');
|
||||
}
|
||||
/**
|
||||
* Joins URL parts into an URL using forward slash.
|
||||
* Forward slash usages are normalised to one between parts.
|
||||
* This method takes variable number of parameters.
|
||||
*
|
||||
* @param $...
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function joinUrlParts()
|
||||
{
|
||||
if (0 === func_num_args()) {
|
||||
throw new \InvalidArgumentException('Need at least one argument');
|
||||
}
|
||||
|
||||
$parts = func_get_args();
|
||||
$trimSlashes = function(&$part) {
|
||||
$part = trim($part, '/');
|
||||
};
|
||||
array_walk($parts, $trimSlashes);
|
||||
$parts = func_get_args();
|
||||
$trimSlashes = function (&$part) {
|
||||
$part = trim($part, '/');
|
||||
};
|
||||
array_walk($parts, $trimSlashes);
|
||||
|
||||
return implode('/', $parts);
|
||||
}
|
||||
return implode('/', $parts);
|
||||
}
|
||||
|
||||
public function canIntercept() {
|
||||
$driver = $this->getSession()->getDriver();
|
||||
if ($driver instanceof GoutteDriver) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if ($driver instanceof Selenium2Driver) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function canIntercept()
|
||||
{
|
||||
$driver = $this->getSession()->getDriver();
|
||||
if ($driver instanceof GoutteDriver) {
|
||||
return true;
|
||||
} else {
|
||||
if ($driver instanceof Selenium2Driver) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedDriverActionException('You need to tag the scenario with "@mink:goutte" or
|
||||
throw new UnsupportedDriverActionException('You need to tag the scenario with "@mink:goutte" or
|
||||
"@mink:symfony". Intercepting the redirections is not supported by %s', $driver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^(.*) without redirection$/
|
||||
*/
|
||||
public function theRedirectionsAreIntercepted($step) {
|
||||
if ($this->canIntercept()) {
|
||||
$this->getSession()->getDriver()->getClient()->followRedirects(false);
|
||||
}
|
||||
/**
|
||||
* @Given /^(.*) without redirection$/
|
||||
*/
|
||||
public function theRedirectionsAreIntercepted($step)
|
||||
{
|
||||
if ($this->canIntercept()) {
|
||||
$this->getSession()->getDriver()->getClient()->followRedirects(false);
|
||||
}
|
||||
|
||||
return new Step\Given($step);
|
||||
}
|
||||
return new Step\Given($step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in form field with specified id|name|label|value.
|
||||
* Overwritten to select the first *visible* element, see https://github.com/Behat/Mink/issues/311
|
||||
*/
|
||||
public function fillField($field, $value) {
|
||||
$value = $this->fixStepArgument($value);
|
||||
$fields = $this->getSession()->getPage()->findAll('named', array(
|
||||
'field', $this->getSession()->getSelectorsHandler()->xpathLiteral($field)
|
||||
));
|
||||
if($fields) foreach($fields as $f) {
|
||||
if($f->isVisible()) {
|
||||
$f->setValue($value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Fills in form field with specified id|name|label|value.
|
||||
* Overwritten to select the first *visible* element, see https://github.com/Behat/Mink/issues/311
|
||||
*/
|
||||
public function fillField($field, $value)
|
||||
{
|
||||
$value = $this->fixStepArgument($value);
|
||||
$fields = $this->getSession()->getPage()->findAll('named', array(
|
||||
'field', $this->getSession()->getSelectorsHandler()->xpathLiteral($field)
|
||||
));
|
||||
if ($fields) {
|
||||
foreach ($fields as $f) {
|
||||
if ($f->isVisible()) {
|
||||
$f->setValue($value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new ElementNotFoundException(
|
||||
$this->getSession(), 'form field', 'id|name|label|value', $field
|
||||
);
|
||||
}
|
||||
throw new ElementNotFoundException(
|
||||
$this->getSession(),
|
||||
'form field',
|
||||
'id|name|label|value',
|
||||
$field
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten to click the first *visable* link the DOM.
|
||||
*/
|
||||
public function clickLink($link) {
|
||||
$link = $this->fixStepArgument($link);
|
||||
$links = $this->getSession()->getPage()->findAll('named', array(
|
||||
'link', $this->getSession()->getSelectorsHandler()->xpathLiteral($link)
|
||||
));
|
||||
if($links) foreach($links as $l) {
|
||||
if($l->isVisible()) {
|
||||
$l->click();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new ElementNotFoundException(
|
||||
$this->getSession(), 'link', 'id|name|label|value', $link
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Overwritten to click the first *visable* link the DOM.
|
||||
*/
|
||||
public function clickLink($link)
|
||||
{
|
||||
$link = $this->fixStepArgument($link);
|
||||
$links = $this->getSession()->getPage()->findAll('named', array(
|
||||
'link', $this->getSession()->getSelectorsHandler()->xpathLiteral($link)
|
||||
));
|
||||
if ($links) {
|
||||
foreach ($links as $l) {
|
||||
if ($l->isVisible()) {
|
||||
$l->click();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new ElementNotFoundException(
|
||||
$this->getSession(),
|
||||
'link',
|
||||
'id|name|label|value',
|
||||
$link
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current date. Relies on the underlying functionality using
|
||||
* {@link SS_Datetime::now()} rather than PHP's system time methods like date().
|
||||
* Supports ISO fomat: Y-m-d
|
||||
* Example: Given the current date is "2009-10-31"
|
||||
*
|
||||
* @Given /^the current date is "([^"]*)"$/
|
||||
*/
|
||||
public function givenTheCurrentDateIs($date) {
|
||||
$newDatetime = \DateTime::createFromFormat('Y-m-d', $date);
|
||||
if(!$newDatetime) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid date format: %s (requires "Y-m-d")', $date));
|
||||
}
|
||||
/**
|
||||
* Sets the current date. Relies on the underlying functionality using
|
||||
* {@link SS_Datetime::now()} rather than PHP's system time methods like date().
|
||||
* Supports ISO fomat: Y-m-d
|
||||
* Example: Given the current date is "2009-10-31"
|
||||
*
|
||||
* @Given /^the current date is "([^"]*)"$/
|
||||
*/
|
||||
public function givenTheCurrentDateIs($date)
|
||||
{
|
||||
$newDatetime = \DateTime::createFromFormat('Y-m-d', $date);
|
||||
if (!$newDatetime) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid date format: %s (requires "Y-m-d")', $date));
|
||||
}
|
||||
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
$oldDatetime = \DateTime::createFromFormat('Y-m-d H:i:s', isset($state->datetime) ? $state->datetime : null);
|
||||
if($oldDatetime) {
|
||||
$newDatetime->setTime($oldDatetime->format('H'), $oldDatetime->format('i'), $oldDatetime->format('s'));
|
||||
}
|
||||
$state->datetime = $newDatetime->format('Y-m-d H:i:s');
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
$oldDatetime = \DateTime::createFromFormat('Y-m-d H:i:s', isset($state->datetime) ? $state->datetime : null);
|
||||
if ($oldDatetime) {
|
||||
$newDatetime->setTime($oldDatetime->format('H'), $oldDatetime->format('i'), $oldDatetime->format('s'));
|
||||
}
|
||||
$state->datetime = $newDatetime->format('Y-m-d H:i:s');
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current time. Relies on the underlying functionality using
|
||||
* {@link \SS_Datetime::now()} rather than PHP's system time methods like date().
|
||||
* Supports ISO fomat: H:i:s
|
||||
* Example: Given the current time is "20:31:50"
|
||||
*
|
||||
* @Given /^the current time is "([^"]*)"$/
|
||||
*/
|
||||
public function givenTheCurrentTimeIs($time) {
|
||||
$newDatetime = \DateTime::createFromFormat('H:i:s', $date);
|
||||
if(!$newDatetime) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid date format: %s (requires "H:i:s")', $date));
|
||||
}
|
||||
/**
|
||||
* Sets the current time. Relies on the underlying functionality using
|
||||
* {@link \SS_Datetime::now()} rather than PHP's system time methods like date().
|
||||
* Supports ISO fomat: H:i:s
|
||||
* Example: Given the current time is "20:31:50"
|
||||
*
|
||||
* @Given /^the current time is "([^"]*)"$/
|
||||
*/
|
||||
public function givenTheCurrentTimeIs($time)
|
||||
{
|
||||
$newDatetime = \DateTime::createFromFormat('H:i:s', $date);
|
||||
if (!$newDatetime) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid date format: %s (requires "H:i:s")', $date));
|
||||
}
|
||||
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
$oldDatetime = \DateTime::createFromFormat('Y-m-d H:i:s', isset($state->datetime) ? $state->datetime : null);
|
||||
if($oldDatetime) {
|
||||
$newDatetime->setDate($oldDatetime->format('Y'), $oldDatetime->format('m'), $oldDatetime->format('d'));
|
||||
}
|
||||
$state->datetime = $newDatetime->format('Y-m-d H:i:s');
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
$oldDatetime = \DateTime::createFromFormat('Y-m-d H:i:s', isset($state->datetime) ? $state->datetime : null);
|
||||
if ($oldDatetime) {
|
||||
$newDatetime->setDate($oldDatetime->format('Y'), $oldDatetime->format('m'), $oldDatetime->format('d'));
|
||||
}
|
||||
$state->datetime = $newDatetime->format('Y-m-d H:i:s');
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects option in select field with specified id|name|label|value.
|
||||
*
|
||||
* @override /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/
|
||||
*/
|
||||
public function selectOption($select, $option) {
|
||||
// Find field
|
||||
$field = $this
|
||||
->getSession()
|
||||
->getPage()
|
||||
->findField($this->fixStepArgument($select));
|
||||
/**
|
||||
* Selects option in select field with specified id|name|label|value.
|
||||
*
|
||||
* @override /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/
|
||||
*/
|
||||
public function selectOption($select, $option)
|
||||
{
|
||||
// Find field
|
||||
$field = $this
|
||||
->getSession()
|
||||
->getPage()
|
||||
->findField($this->fixStepArgument($select));
|
||||
|
||||
// If field is visible then select it as per normal
|
||||
if($field && $field->isVisible()) {
|
||||
parent::selectOption($select, $option);
|
||||
} else {
|
||||
$this->selectOptionWithJavascript($select, $option);
|
||||
}
|
||||
}
|
||||
// If field is visible then select it as per normal
|
||||
if ($field && $field->isVisible()) {
|
||||
parent::selectOption($select, $option);
|
||||
} else {
|
||||
$this->selectOptionWithJavascript($select, $option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects option in select field with specified id|name|label|value using javascript
|
||||
* This method uses javascript to allow selection of options that may be
|
||||
* overridden by javascript libraries, and thus hide the element.
|
||||
*
|
||||
* @When /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)" with javascript$/
|
||||
*/
|
||||
public function selectOptionWithJavascript($select, $option) {
|
||||
$select = $this->fixStepArgument($select);
|
||||
$option = $this->fixStepArgument($option);
|
||||
$page = $this->getSession()->getPage();
|
||||
/**
|
||||
* Selects option in select field with specified id|name|label|value using javascript
|
||||
* This method uses javascript to allow selection of options that may be
|
||||
* overridden by javascript libraries, and thus hide the element.
|
||||
*
|
||||
* @When /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)" with javascript$/
|
||||
*/
|
||||
public function selectOptionWithJavascript($select, $option)
|
||||
{
|
||||
$select = $this->fixStepArgument($select);
|
||||
$option = $this->fixStepArgument($option);
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
// Find field
|
||||
$field = $page->findField($select);
|
||||
if (null === $field) {
|
||||
throw new ElementNotFoundException($this->getSession(), 'form field', 'id|name|label|value', $select);
|
||||
}
|
||||
// Find field
|
||||
$field = $page->findField($select);
|
||||
if (null === $field) {
|
||||
throw new ElementNotFoundException($this->getSession(), 'form field', 'id|name|label|value', $select);
|
||||
}
|
||||
|
||||
// Find option
|
||||
$opt = $field->find('named', array(
|
||||
'option', $this->getSession()->getSelectorsHandler()->xpathLiteral($option)
|
||||
));
|
||||
if (null === $opt) {
|
||||
throw new ElementNotFoundException($this->getSession(), 'select option', 'value|text', $option);
|
||||
}
|
||||
// Find option
|
||||
$opt = $field->find('named', array(
|
||||
'option', $this->getSession()->getSelectorsHandler()->xpathLiteral($option)
|
||||
));
|
||||
if (null === $opt) {
|
||||
throw new ElementNotFoundException($this->getSession(), 'select option', 'value|text', $option);
|
||||
}
|
||||
|
||||
// Merge new option in with old handling both multiselect and single select
|
||||
$value = $field->getValue();
|
||||
$newValue = $opt->getAttribute('value');
|
||||
if(is_array($value)) {
|
||||
if(!in_array($newValue, $value)) $value[] = $newValue;
|
||||
} else {
|
||||
$value = $newValue;
|
||||
}
|
||||
$valueEncoded = json_encode($value);
|
||||
// Merge new option in with old handling both multiselect and single select
|
||||
$value = $field->getValue();
|
||||
$newValue = $opt->getAttribute('value');
|
||||
if (is_array($value)) {
|
||||
if (!in_array($newValue, $value)) {
|
||||
$value[] = $newValue;
|
||||
}
|
||||
} else {
|
||||
$value = $newValue;
|
||||
}
|
||||
$valueEncoded = json_encode($value);
|
||||
|
||||
// Inject this value via javascript
|
||||
$fieldID = $field->getAttribute('ID');
|
||||
$script = <<<EOS
|
||||
// Inject this value via javascript
|
||||
$fieldID = $field->getAttribute('ID');
|
||||
$script = <<<EOS
|
||||
(function($) {
|
||||
$("#$fieldID")
|
||||
.val($valueEncoded)
|
||||
@ -497,7 +539,6 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||
.trigger('chosen:updated');
|
||||
})(jQuery);
|
||||
EOS;
|
||||
$this->getSession()->getDriver()->executeScript($script);
|
||||
}
|
||||
|
||||
$this->getSession()->getDriver()->executeScript($script);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
namespace SilverStripe\BehatExtension;
|
||||
|
||||
use Symfony\Component\Config\FileLocator,
|
||||
Symfony\Component\DependencyInjection\ContainerBuilder,
|
||||
Symfony\Component\DependencyInjection\Loader\YamlFileLoader,
|
||||
Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
|
||||
use Behat\Behat\Extension\ExtensionInterface;
|
||||
|
||||
@ -41,7 +41,8 @@ class Extension implements ExtensionInterface
|
||||
$loader->load('silverstripe.yml');
|
||||
|
||||
$behatBasePath = $container->getParameter('behat.paths.base');
|
||||
$config['framework_path'] = realpath(sprintf('%s%s%s',
|
||||
$config['framework_path'] = realpath(sprintf(
|
||||
'%s%s%s',
|
||||
rtrim($behatBasePath, DIRECTORY_SEPARATOR),
|
||||
DIRECTORY_SEPARATOR,
|
||||
ltrim($config['framework_path'], DIRECTORY_SEPARATOR)
|
||||
@ -59,7 +60,7 @@ class Extension implements ExtensionInterface
|
||||
$container->setParameter('behat.silverstripe_extension.ajax_steps', $config['ajax_steps']);
|
||||
}
|
||||
if (isset($config['region_map'])) {
|
||||
$container->setParameter('behat.silverstripe_extension.region_map', $config['region_map']);
|
||||
$container->setParameter('behat.silverstripe_extension.region_map', $config['region_map']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +79,7 @@ class Extension implements ExtensionInterface
|
||||
*
|
||||
* @param ArrayNodeDefinition $builder
|
||||
*/
|
||||
function getConfig(ArrayNodeDefinition $builder)
|
||||
public function getConfig(ArrayNodeDefinition $builder)
|
||||
{
|
||||
$builder->
|
||||
children()->
|
||||
|
@ -16,5 +16,4 @@ class MinkExtension extends \Behat\MinkExtension\Extension
|
||||
parent::getCompilerPasses()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,124 +7,151 @@ namespace SilverStripe\BehatExtension\Utility;
|
||||
* but saves emails in {@link TestSessionEnvironment}
|
||||
* to share the state between PHP calls (CLI vs. browser).
|
||||
*/
|
||||
class TestMailer extends \Mailer {
|
||||
class TestMailer extends \Mailer
|
||||
{
|
||||
|
||||
/**
|
||||
* @var TestSessionEnvironment
|
||||
*/
|
||||
protected $testSessionEnvironment;
|
||||
/**
|
||||
* @var TestSessionEnvironment
|
||||
*/
|
||||
protected $testSessionEnvironment;
|
||||
|
||||
public function __construct() {
|
||||
$this->testSessionEnvironment = \Injector::inst()->get('TestSessionEnvironment');
|
||||
}
|
||||
public function __construct()
|
||||
{
|
||||
$this->testSessionEnvironment = \Injector::inst()->get('TestSessionEnvironment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a plain-text email.
|
||||
* TestMailer will merely record that the email was asked to be sent, without sending anything.
|
||||
*/
|
||||
public function sendPlain($to, $from, $subject, $plainContent, $attachedFiles = false, $customHeaders = false) {
|
||||
$this->saveEmail(array(
|
||||
'Type' => 'plain',
|
||||
'To' => $to,
|
||||
'From' => $from,
|
||||
'Subject' => $subject,
|
||||
'Content' => $plainContent,
|
||||
'PlainContent' => $plainContent,
|
||||
'AttachedFiles' => $attachedFiles,
|
||||
'CustomHeaders' => $customHeaders,
|
||||
));
|
||||
/**
|
||||
* Send a plain-text email.
|
||||
* TestMailer will merely record that the email was asked to be sent, without sending anything.
|
||||
*/
|
||||
public function sendPlain($to, $from, $subject, $plainContent, $attachedFiles = false, $customHeaders = false)
|
||||
{
|
||||
$this->saveEmail(array(
|
||||
'Type' => 'plain',
|
||||
'To' => $to,
|
||||
'From' => $from,
|
||||
'Subject' => $subject,
|
||||
'Content' => $plainContent,
|
||||
'PlainContent' => $plainContent,
|
||||
'AttachedFiles' => $attachedFiles,
|
||||
'CustomHeaders' => $customHeaders,
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part HTML email
|
||||
* TestMailer will merely record that the email was asked to be sent, without sending anything.
|
||||
*/
|
||||
public function sendHTML($to, $from, $subject, $htmlContent, $attachedFiles = false, $customHeaders = false,
|
||||
$plainContent = false, $inlineImages = false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part HTML email
|
||||
* TestMailer will merely record that the email was asked to be sent, without sending anything.
|
||||
*/
|
||||
public function sendHTML(
|
||||
$to,
|
||||
$from,
|
||||
$subject,
|
||||
$htmlContent,
|
||||
$attachedFiles = false,
|
||||
$customHeaders = false,
|
||||
$plainContent = false,
|
||||
$inlineImages = false
|
||||
) {
|
||||
|
||||
$this->saveEmail(array(
|
||||
'Type' => 'html',
|
||||
'To' => $to,
|
||||
'From' => $from,
|
||||
'Subject' => $subject,
|
||||
'Content' => $htmlContent,
|
||||
'PlainContent' => $plainContent,
|
||||
'AttachedFiles' => $attachedFiles,
|
||||
'CustomHeaders' => $customHeaders,
|
||||
));
|
||||
|
||||
$this->saveEmail(array(
|
||||
'Type' => 'html',
|
||||
'To' => $to,
|
||||
'From' => $from,
|
||||
'Subject' => $subject,
|
||||
'Content' => $htmlContent,
|
||||
'PlainContent' => $plainContent,
|
||||
'AttachedFiles' => $attachedFiles,
|
||||
'CustomHeaders' => $customHeaders,
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the log of emails sent
|
||||
*/
|
||||
public function clearEmails()
|
||||
{
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
if (isset($state->emails)) {
|
||||
unset($state->emails);
|
||||
}
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the log of emails sent
|
||||
*/
|
||||
public function clearEmails() {
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
if(isset($state->emails)) unset($state->emails);
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for an email that was sent.
|
||||
* All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression.
|
||||
*
|
||||
* @param $to
|
||||
* @param $from
|
||||
* @param $subject
|
||||
* @param $content
|
||||
* @return array Contains the keys: 'type', 'to', 'from', 'subject', 'content', 'plainContent', 'attachedFiles',
|
||||
* 'customHeaders', 'htmlContent', 'inlineImages'
|
||||
*/
|
||||
public function findEmail($to = null, $from = null, $subject = null, $content = null) {
|
||||
$matches = $this->findEmails($to, $from, $subject, $content);
|
||||
/**
|
||||
* Search for an email that was sent.
|
||||
* All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression.
|
||||
*
|
||||
* @param $to
|
||||
* @param $from
|
||||
* @param $subject
|
||||
* @param $content
|
||||
* @return array Contains the keys: 'type', 'to', 'from', 'subject', 'content', 'plainContent', 'attachedFiles',
|
||||
* 'customHeaders', 'htmlContent', 'inlineImages'
|
||||
*/
|
||||
public function findEmail($to = null, $from = null, $subject = null, $content = null)
|
||||
{
|
||||
$matches = $this->findEmails($to, $from, $subject, $content);
|
||||
//got the count of matches emails
|
||||
$emailCount = count($matches);
|
||||
//get the last(latest) one
|
||||
return $matches ? $matches[$emailCount-1] : null;
|
||||
}
|
||||
return $matches ? $matches[$emailCount-1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all emails.
|
||||
* All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression.
|
||||
*
|
||||
* @param $to
|
||||
* @param $from
|
||||
* @param $subject
|
||||
* @param $content
|
||||
* @return array Contains the keys: 'type', 'to', 'from', 'subject', 'content', 'plainContent', 'attachedFiles',
|
||||
* 'customHeaders', 'htmlContent', 'inlineImages'
|
||||
*/
|
||||
public function findEmails($to = null, $from = null, $subject = null, $content = null) {
|
||||
$matches = array();
|
||||
$args = func_get_args();
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
$emails = isset($state->emails) ? $state->emails : array();
|
||||
foreach($emails as $email) {
|
||||
$matched = true;
|
||||
/**
|
||||
* Search for all emails.
|
||||
* All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression.
|
||||
*
|
||||
* @param $to
|
||||
* @param $from
|
||||
* @param $subject
|
||||
* @param $content
|
||||
* @return array Contains the keys: 'type', 'to', 'from', 'subject', 'content', 'plainContent', 'attachedFiles',
|
||||
* 'customHeaders', 'htmlContent', 'inlineImages'
|
||||
*/
|
||||
public function findEmails($to = null, $from = null, $subject = null, $content = null)
|
||||
{
|
||||
$matches = array();
|
||||
$args = func_get_args();
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
$emails = isset($state->emails) ? $state->emails : array();
|
||||
foreach ($emails as $email) {
|
||||
$matched = true;
|
||||
|
||||
foreach(array('To','From','Subject','Content') as $i => $field) {
|
||||
if(!isset($email->$field)) continue;
|
||||
$value = (isset($args[$i])) ? $args[$i] : null;
|
||||
if($value) {
|
||||
if($value[0] == '/') $matched = preg_match($value, $email->$field);
|
||||
else $matched = ($value == $email->$field);
|
||||
if(!$matched) break;
|
||||
}
|
||||
}
|
||||
if($matched) $matches[] = $email;
|
||||
}
|
||||
foreach (array('To', 'From', 'Subject', 'Content') as $i => $field) {
|
||||
if (!isset($email->$field)) {
|
||||
continue;
|
||||
}
|
||||
$value = (isset($args[$i])) ? $args[$i] : null;
|
||||
if ($value) {
|
||||
if ($value[0] == '/') {
|
||||
$matched = preg_match($value, $email->$field);
|
||||
} else {
|
||||
$matched = ($value == $email->$field);
|
||||
}
|
||||
if (!$matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($matched) {
|
||||
$matches[] = $email;
|
||||
}
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
protected function saveEmail($data) {
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
if(!isset($state->emails)) $state->emails = array();
|
||||
$state->emails[] = array_filter($data);
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
return $matches;
|
||||
}
|
||||
|
||||
protected function saveEmail($data)
|
||||
{
|
||||
$state = $this->testSessionEnvironment->getState();
|
||||
if (!isset($state->emails)) {
|
||||
$state->emails = array();
|
||||
}
|
||||
$state->emails[] = array_filter($data);
|
||||
$this->testSessionEnvironment->applyState($state);
|
||||
}
|
||||
}
|
||||
|
@ -1,83 +1,90 @@
|
||||
<?php
|
||||
namespace SilverStripe\BehatExtension\Tests;
|
||||
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeContext,
|
||||
Behat\Mink\Mink;
|
||||
use SilverStripe\BehatExtension\Context\SilverStripeContext;
|
||||
use Behat\Mink\Mink;
|
||||
|
||||
class SilverStripeContextTest extends \PHPUnit_Framework_TestCase {
|
||||
class SilverStripeContextTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
protected $backupGlobals = false;
|
||||
protected $backupGlobals = false;
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot find 'region_map' in the behat.yml
|
||||
*/
|
||||
public function testGetRegionObjThrowsExceptionOnUnknownSelector() {
|
||||
$context = $this->getContextMock();
|
||||
$context->getRegionObj('.unknown');
|
||||
}
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot find 'region_map' in the behat.yml
|
||||
*/
|
||||
public function testGetRegionObjThrowsExceptionOnUnknownSelector()
|
||||
{
|
||||
$context = $this->getContextMock();
|
||||
$context->getRegionObj('.unknown');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot find the specified region in the behat.yml
|
||||
*/
|
||||
public function testGetRegionObjThrowsExceptionOnUnknownRegion() {
|
||||
$context = $this->getContextMock();
|
||||
$context->setRegionMap(array('MyRegion' => '.my-region'));
|
||||
$context->getRegionObj('.unknown');
|
||||
}
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot find the specified region in the behat.yml
|
||||
*/
|
||||
public function testGetRegionObjThrowsExceptionOnUnknownRegion()
|
||||
{
|
||||
$context = $this->getContextMock();
|
||||
$context->setRegionMap(array('MyRegion' => '.my-region'));
|
||||
$context->getRegionObj('.unknown');
|
||||
}
|
||||
|
||||
public function testGetRegionObjFindsBySelector() {
|
||||
$context = $this->getContextMock();
|
||||
$context->getSession()->getPage()
|
||||
->expects($this->any())
|
||||
->method('find')
|
||||
->will($this->returnValue($this->getElementMock()));
|
||||
$obj = $context->getRegionObj('.some-selector');
|
||||
$this->assertNotNull($obj);
|
||||
}
|
||||
public function testGetRegionObjFindsBySelector()
|
||||
{
|
||||
$context = $this->getContextMock();
|
||||
$context->getSession()->getPage()
|
||||
->expects($this->any())
|
||||
->method('find')
|
||||
->will($this->returnValue($this->getElementMock()));
|
||||
$obj = $context->getRegionObj('.some-selector');
|
||||
$this->assertNotNull($obj);
|
||||
}
|
||||
|
||||
public function testGetRegionObjFindsByRegion() {
|
||||
$context = $this->getContextMock();
|
||||
$el = $this->getElementMock();
|
||||
$context->getSession()->getPage()
|
||||
->expects($this->any())
|
||||
->method('find')
|
||||
->will($this->returnCallback(function($type, $selector) use ($el) {
|
||||
return ($selector == '.my-region') ? $el : null;
|
||||
}));
|
||||
$context->setRegionMap(array('MyRegion' => '.my-asdf'));
|
||||
$obj = $context->getRegionObj('.my-region');
|
||||
$this->assertNotNull($obj);
|
||||
}
|
||||
public function testGetRegionObjFindsByRegion()
|
||||
{
|
||||
$context = $this->getContextMock();
|
||||
$el = $this->getElementMock();
|
||||
$context->getSession()->getPage()
|
||||
->expects($this->any())
|
||||
->method('find')
|
||||
->will($this->returnCallback(function ($type, $selector) use ($el) {
|
||||
return ($selector == '.my-region') ? $el : null;
|
||||
}));
|
||||
$context->setRegionMap(array('MyRegion' => '.my-asdf'));
|
||||
$obj = $context->getRegionObj('.my-region');
|
||||
$this->assertNotNull($obj);
|
||||
}
|
||||
|
||||
protected function getContextMock() {
|
||||
$pageMock = $this->getMockBuilder('Behat\Mink\Element\DocumentElement')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('find'))
|
||||
->getMock();
|
||||
$sessionMock = $this->getMockBuilder('Behat\Mink\Session')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Behat\Mink\Driver\DriverInterface'),
|
||||
$this->getMock('Behat\Mink\Selector\SelectorsHandler')
|
||||
))
|
||||
->setMethods(array('getPage'))
|
||||
->getMock();
|
||||
$sessionMock->expects($this->any())
|
||||
->method('getPage')
|
||||
->will($this->returnValue($pageMock));
|
||||
$mink = new Mink(array('default' => $sessionMock));
|
||||
$mink->setDefaultSessionName('default');
|
||||
protected function getContextMock()
|
||||
{
|
||||
$pageMock = $this->getMockBuilder('Behat\Mink\Element\DocumentElement')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('find'))
|
||||
->getMock();
|
||||
$sessionMock = $this->getMockBuilder('Behat\Mink\Session')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Behat\Mink\Driver\DriverInterface'),
|
||||
$this->getMock('Behat\Mink\Selector\SelectorsHandler')
|
||||
))
|
||||
->setMethods(array('getPage'))
|
||||
->getMock();
|
||||
$sessionMock->expects($this->any())
|
||||
->method('getPage')
|
||||
->will($this->returnValue($pageMock));
|
||||
$mink = new Mink(array('default' => $sessionMock));
|
||||
$mink->setDefaultSessionName('default');
|
||||
|
||||
$context = new SilverStripeContext(array());
|
||||
$context->setMink($mink);
|
||||
$context = new SilverStripeContext(array());
|
||||
$context->setMink($mink);
|
||||
|
||||
return $context;
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
protected function getElementMock() {
|
||||
return $this->getMockBuilder('Behat\Mink\Element\Element')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
}
|
||||
protected function getElementMock()
|
||||
{
|
||||
return $this->getMockBuilder('Behat\Mink\Element\Element')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
$frameworkPath = __DIR__ . '/../framework';
|
||||
$frameworkDir = basename($frameworkPath);
|
||||
if(!defined('BASE_PATH')) define('BASE_PATH', dirname($frameworkPath));
|
||||
require_once $frameworkPath . '/core/Core.php';
|
||||
if (!defined('BASE_PATH')) {
|
||||
define('BASE_PATH', dirname($frameworkPath));
|
||||
}
|
||||
require_once $frameworkPath . '/core/Core.php';
|
||||
|
Loading…
Reference in New Issue
Block a user