first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,80 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context\ContextClass;
use Behat\Behat\Context\ContextClass\ClassResolver as Resolver;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Moodle behat context class resolver.
*
* Resolves arbitrary context strings into a context classes.
*
* @see ContextEnvironmentHandler
*
* @package core
* @copyright 2104 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class ClassResolver implements Resolver {
/** @var array keep list of all behat contexts in moodle. */
private $moodlebehatcontexts = null;
/**
* Constructor for ClassResolver class.
*
* @param array $parameters list of params provided to moodle.
*/
public function __construct($parameters) {
$this->moodlebehatcontexts = $parameters['steps_definitions'];
}
/**
* Checks if resolvers supports provided class.
* Moodle behat context class starts with behat_
*
* @param string $contextstring
* @return Boolean
*/
public function supportsClass($contextstring) {
return (strpos($contextstring, 'behat_') === 0);
}
/**
* Resolves context class.
*
* @param string $contextclass
* @return string context class.
*/
public function resolveClass($contextclass) {
if (!is_array($this->moodlebehatcontexts)) {
throw new \RuntimeException('There are no Moodle context with steps definitions');
}
// Using the key as context identifier load context class.
if (
!empty($this->moodlebehatcontexts[$contextclass]) &&
(file_exists($this->moodlebehatcontexts[$contextclass]))
) {
require_once($this->moodlebehatcontexts[$contextclass]);
} else {
throw new \RuntimeException('Moodle behat context "' . $contextclass . '" not found');
}
return $contextclass;
}
}
@@ -0,0 +1,55 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context\Initializer;
use Behat\Behat\Context\Context;
use Behat\Behat\Context\Initializer\ContextInitializer;
use Moodle\BehatExtension\Context\MoodleContext;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* MoodleContext initializer
*
* @package core
* @author David Monllaó <david.monllao@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleAwareInitializer implements ContextInitializer {
/** @var array The list of parameters */
private $parameters;
/**
* Initializes initializer.
*
* @param array $parameters
*/
public function __construct(array $parameters) {
$this->parameters = $parameters;
}
/**
* Initializes provided context.
*
* @param Context $context
*/
public function initializeContext(Context $context) {
if ($context instanceof MoodleContext) {
$context->setMoodleConfig($this->parameters);
}
}
}
@@ -0,0 +1,46 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context;
use Behat\MinkExtension\Context\RawMinkContext;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Moodle contexts loader
*
* It gathers all the available steps definitions reading the
* Moodle configuration file
*
* @package core
* @copyright 2012 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleContext extends RawMinkContext {
/** @var array Moodle features and steps definitions list */
protected $moodleconfig;
/**
* Includes all the specified Moodle subcontexts.
*
* @param array $parameters
*/
public function setMoodleConfig(array $parameters): void {
$this->moodleconfig = $parameters;
}
}
@@ -0,0 +1,68 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context\Step;
use Behat\Gherkin\Node\StepNode;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Chained Step base class.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class ChainedStep extends StepNode {
/**
* @var string
*/
private $language;
// phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod.Found
/**
* Initializes ChainedStep.
*
* @param string $keyword
* @param string $text
* @param array $arguments
* @param int $line
* @param string $keywordtype
*/
public function __construct($keyword, $text, array $arguments, $line = 0, $keywordtype = 'Given') {
parent::__construct($keyword, $text, $arguments, $line, $keywordtype);
}
// phpcs:enable Generic.CodeAnalysis.UselessOverridingMethod.Found
/**
* Sets language.
*
* @param string $language
*/
public function setLanguage($language) {
$this->language = $language;
}
/**
* Returns language.
*
* @return string
*/
public function getLanguage() {
return $this->language;
}
}
@@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context\Step;
/**
* Chained `Given` step.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class Given extends ChainedStep {
/**
* Initializes `Given` sub-step.
*/
public function __construct() {
$arguments = func_get_args();
$text = array_shift($arguments);
parent::__construct('Given', $text, $arguments);
}
}
@@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context\Step;
/**
* Chained `Then` ChainedStep.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class Then extends ChainedStep {
/**
* Initializes `Then` sub-step.
*/
public function __construct() {
$arguments = func_get_args();
$text = array_shift($arguments);
parent::__construct('Then', $text, $arguments);
}
}
@@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Context\Step;
/**
* Chained `When` step.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class When extends ChainedStep {
/**
* Initializes `When` sub-step.
*/
public function __construct() {
$arguments = func_get_args();
$text = array_shift($arguments);
parent::__construct('When', $text, $arguments);
}
}
@@ -0,0 +1,123 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Definition\Cli;
use Behat\Behat\Definition\DefinitionWriter;
use Behat\Behat\Definition\Printer\ConsoleDefinitionListPrinter;
use Behat\Testwork\Cli\Controller;
use Behat\Testwork\Suite\SuiteRepository;
use Moodle\BehatExtension\Definition\Printer\ConsoleDefinitionInformationPrinter;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Available definition controller, for calling moodle information printer.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class AvailableDefinitionsController implements Controller {
/** @var SuiteRepository */
private $suiterepository;
/** @var DefinitionWriter */
private $writer;
/** @var ConsoleDefinitionListPrinter */
private $listprinter;
/** @var ConsoleDefinitionInformationPrinter */
private $infoprinter;
/**
* Initializes controller.
*
* @param SuiteRepository $suiterepository
* @param DefinitionWriter $writer
* @param ConsoleDefinitionListPrinter $listprinter
* @param ConsoleDefinitionInformationPrinter $infoprinter
*/
public function __construct(
SuiteRepository $suiterepository,
DefinitionWriter $writer,
ConsoleDefinitionListPrinter $listprinter,
ConsoleDefinitionInformationPrinter $infoprinter
) {
$this->suiterepository = $suiterepository;
$this->writer = $writer;
$this->listprinter = $listprinter;
$this->infoprinter = $infoprinter;
}
/**
* Configures command to be executable by the controller.
*
* @param Command $command
*/
public function configure(Command $command) {
$command->addOption('--definitions', '-d', InputOption::VALUE_REQUIRED,
"Print all available step definitions:" . PHP_EOL .
"- use <info>--definitions l</info> to just list definition expressions." . PHP_EOL .
"- use <info>--definitions i</info> to show definitions with extended info." . PHP_EOL .
"- use <info>--definitions 'needle'</info> to find specific definitions." . PHP_EOL .
"Use <info>--lang</info> to see definitions in specific language."
);
}
/**
* Executes controller.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return null|integer
*/
public function execute(InputInterface $input, OutputInterface $output) {
if (null === $argument = $input->getOption('definitions')) {
return null;
}
$printer = $this->getdefinitionPrinter($argument);
foreach ($this->suiterepository->getSuites() as $suite) {
$this->writer->printSuiteDefinitions($printer, $suite);
}
return 0;
}
/**
* Returns definition printer for provided option argument.
*
* @param string $argument
*
* @return \Behat\Behat\Definition\Printer\DefinitionPrinter
*/
private function getdefinitionprinter($argument) {
if ('l' === $argument) {
return $this->listprinter;
}
if ('i' !== $argument) {
$this->infoprinter->setSearchCriterion($argument);
}
return $this->infoprinter;
}
}
@@ -0,0 +1,105 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Definition\Printer;
use Behat\Behat\Definition\Printer\ConsoleDefinitionPrinter;
use Behat\Testwork\Suite\Suite;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Moodle console definition information printer.
*
* Used in moodle for definition printing.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class ConsoleDefinitionInformationPrinter extends ConsoleDefinitionPrinter {
/** @var null|string */
private $searchcriterion;
/**
* Sets search criterion.
*
* @param string $criterion
*/
public function setSearchCriterion($criterion) {
$this->searchcriterion = $criterion;
}
/**
* Prints definition.
*
* @param Suite $suite
* @param Definition[] $definitions
*/
public function printDefinitions(Suite $suite, $definitions) {
$template = <<<TPL
<div class="step"><div class="stepdescription">{description}</div>
<div class="stepcontent"><span class="steptype">{type}</span><span class="stepregex">{regex}</span></div>
<div class="stepapipath">{apipath}</div>
</div>
TPL;
$search = $this->searchcriterion;
// If there is a specific type (given, when or then) required.
if ($search && strpos($search, '&&') !== false) {
list($search, $type) = explode('&&', $search);
}
foreach ($definitions as $definition) {
$definition = $this->translateDefinition($suite, $definition);
if (!empty($type) && strtolower($definition->getType()) != $type) {
continue;
}
$pattern = $definition->getPattern();
if ($search && !preg_match('/' . str_replace(' ', '.*', preg_quote($search, '/') . '/'), $pattern)) {
continue;
}
$description = $definition->getDescription();
// Removing beginning and end.
$pattern = substr($pattern, 2, strlen($pattern) - 4);
// Replacing inline regex for expected info string.
$pattern = preg_replace_callback(
'/"\(\?P<([^>]*)>(.*?)"( |$)/',
function ($matches) {
return '"' . strtoupper($matches[1]) . '" ';
},
$pattern
);
$definitiontoprint[] = strtr($template, [
'{regex}' => $pattern,
'{type}' => str_pad($definition->getType(), 5, ' ', STR_PAD_LEFT),
'{description}' => $description ? $description : '',
'{apipath}' => $definition->getPath()
]);
$this->write(implode("\n", $definitiontoprint));
unset($definitiontoprint);
}
}
}
@@ -0,0 +1,94 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Driver;
use Behat\Mink\Exception\DriverException;
use OAndreyev\Mink\Driver\WebDriver as UpstreamDriver;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* WebDriver Driver to allow extra selenium capabilities required by Moodle.
*
* @package core
* @copyright 2016 onwards Rajesh Taneja
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class WebDriver extends UpstreamDriver {
/**
* Dirty attribute to get the browser name; $browserName is private
* @var string
*/
protected static $browser;
/**
* Instantiates the driver.
*
* @param string $browsername Browser name
* @param array $desiredcapabilities The desired capabilities
* @param string $wdhost The WebDriver host
* @param array $moodleparameters Moodle parameters including our non-behat-friendly selenium capabilities
*/
public function __construct(
$browsername = 'chrome',
$desiredcapabilities = null,
$wdhost = 'http://localhost:4444/wd/hub',
$moodleparameters = []
) {
parent::__construct($browsername, $desiredcapabilities, $wdhost);
// This class is instantiated by the dependencies injection system so prior to all of beforeSuite subscribers
// which will call getBrowser*().
self::$browser = $browsername;
}
/**
* Returns the browser being used.
*
* We need to know it:
* - To show info about the run.
* - In case there are differences between browsers in the steps.
*
* @return string
*/
public static function getBrowserName() {
return self::$browser;
}
/**
* Post key on specified xpath.
*
* @param string $key
* @param string $xpath
*/
public function post_key($key, $xpath) {
throw new \Exception('No longer used - please use keyDown and keyUp');
}
#[\Override]
public function stop(): void {
try {
parent::stop();
} catch (DriverException $e) {
error_log($e->getMessage());
$rcp = new \ReflectionProperty(parent::class, 'webDriver');
$rcp->setValue($this, null);
}
}
}
@@ -0,0 +1,91 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Driver;
use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory;
use OAndreyev\Mink\Driver\WebDriverFactory as UpstreamFactory;
use Symfony\Component\DependencyInjection\Definition;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Driver factory for the Moodle WebDriver.
*
* @package core
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class WebDriverFactory extends UpstreamFactory implements DriverFactory {
/**
* Builds the service definition for the driver.
*
* @param array $config
* @return Definition
*/
public function buildDriver(array $config) {
// Merge capabilities.
$extracapabilities = $config['capabilities']['extra_capabilities'];
unset($config['capabilities']['extra_capabilities']);
// Normalise the Edge browser name.
if ($config['browser'] === 'edge') {
$config['browser'] = 'MicrosoftEdge';
}
// Ensure that the capabilites.browserName is set correctly.
$config['capabilities']['browserName'] = $config['browser'];
$capabilities = array_replace($extracapabilities, $config['capabilities']);
// Incorrect top level capabilities lead to invalid Selenium browser selection.
// See https://github.com/SeleniumHQ/selenium/issues/10410 for more information.
// If any of these settings are mentioned then additional empty Capability options are created and a random
// browser is chosen.
$filteredcapabilities = [
'tags',
'ignoreZoomSetting',
'marionette',
'browser',
'name',
];
foreach ($filteredcapabilities as $capabilityname) {
unset($capabilities[$capabilityname]);
}
// Build driver definition.
return new Definition(WebDriver::class, [
$config['browser'],
$capabilities,
$config['wd_host'],
]);
}
/**
* Get the CapabilitiesNode.
*
* @return Node
*/
protected function getCapabilitiesNode() {
$node = parent::getCapabilitiesNode();
// Specify chrome as the default browser.
$node->find('browser')->defaultValue('chrome');
return $node;
}
}
@@ -0,0 +1,280 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\EventDispatcher\Tester;
use Behat\Behat\EventDispatcher\Event\AfterStepSetup;
use Behat\Behat\EventDispatcher\Event\AfterStepTested;
use Behat\Behat\EventDispatcher\Event\BeforeStepTeardown;
use Behat\Behat\EventDispatcher\Event\BeforeStepTested;
use Behat\Behat\Tester\Result\ExecutedStepResult;
use Behat\Behat\Tester\Result\SkippedStepResult;
use Behat\Behat\Tester\Result\StepResult;
use Behat\Behat\Tester\Result\UndefinedStepResult;
use Behat\Behat\Tester\StepTester;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\StepNode;
use Behat\Testwork\Call\CallResult;
use Behat\Testwork\Environment\Environment;
use Behat\Testwork\EventDispatcher\TestworkEventDispatcher;
use Moodle\BehatExtension\Context\Step\ChainedStep;
use Moodle\BehatExtension\Exception\SkippedException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Override step tester to ensure chained steps gets executed.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class ChainedStepTester implements StepTester {
/**
* The text of the step to look for exceptions / debugging messages.
*/
const EXCEPTIONS_STEP_TEXT = 'I look for exceptions';
/**
* @var StepTester Base step tester.
*/
private $singlesteptester;
/**
* @var EventDispatcher keep step event dispatcher.
*/
private $eventdispatcher;
/**
* Keep status of chained steps if used.
* @var bool
*/
protected static $chainedstepused = false;
/**
* Constructor.
*
* @param StepTester $steptester single step tester.
*/
public function __construct(StepTester $steptester) {
$this->singlesteptester = $steptester;
}
/**
* Set event dispatcher to use for events.
*
* @param EventDispatcherInterface $eventdispatcher
*/
public function setEventDispatcher(EventDispatcherInterface $eventdispatcher) {
$this->eventdispatcher = $eventdispatcher;
}
/**
* Sets up step for a test.
*
* @param Environment $env
* @param FeatureNode $feature
* @param StepNode $step
* @param bool $skip
*
* @return Setup
*/
public function setUp(Environment $env, FeatureNode $feature, StepNode $step, $skip) {
return $this->singlesteptester->setUp($env, $feature, $step, $skip);
}
/**
* Tests step.
*
* @param Environment $env
* @param FeatureNode $feature
* @param StepNode $step
* @param bool $skip
* @return StepResult
*/
public function test(Environment $env, FeatureNode $feature, StepNode $step, $skip) {
$result = $this->singlesteptester->test($env, $feature, $step, $skip);
if (!($result instanceof ExecutedStepResult) || !$this->supportsResult($result->getCallResult())) {
$result = $this->checkSkipResult($result);
// If undefined step then don't continue chained steps.
if ($result instanceof UndefinedStepResult) {
return $result;
}
// If exception caught, then don't continue chained steps.
if (($result instanceof ExecutedStepResult) && $result->hasException()) {
return $result;
}
// If step is skipped, then return. no need to continue chain steps.
if ($result instanceof SkippedStepResult) {
return $result;
}
// Check for exceptions.
// Extra step, looking for a moodle exception, a debugging() message or a PHP debug message.
$checkingstep = new StepNode('Given', self::EXCEPTIONS_STEP_TEXT, [], $step->getLine());
$afterexceptioncheckingevent = $this->singlesteptester->test($env, $feature, $checkingstep, $skip);
$exceptioncheckresult = $this->checkSkipResult($afterexceptioncheckingevent);
if (!$exceptioncheckresult->isPassed()) {
return $exceptioncheckresult;
}
return $result;
}
return $this->runChainedSteps($env, $feature, $result, $skip);
}
/**
* Tears down step after a test.
*
* @param Environment $env
* @param FeatureNode $feature
* @param StepNode $step
* @param bool $skip
* @param StepResult $result
* @return Teardown
*/
public function tearDown(Environment $env, FeatureNode $feature, StepNode $step, $skip, StepResult $result) {
return $this->singlesteptester->tearDown($env, $feature, $step, $skip, $result);
}
/**
* Check if results supported.
*
* @param CallResult $result
* @return bool
*/
private function supportsResult(CallResult $result) {
$return = $result->getReturn();
if ($return instanceof ChainedStep) {
return true;
}
if (!is_array($return) || empty($return)) {
return false;
}
foreach ($return as $value) {
if (!$value instanceof ChainedStep) {
return false;
}
}
return true;
}
/**
* Run chained steps.
*
* @param Environment $env
* @param FeatureNode $feature
* @param ExecutedStepResult $result
* @param bool $skip
* @return ExecutedStepResult|StepResult
*/
private function runChainedSteps(Environment $env, FeatureNode $feature, ExecutedStepResult $result, $skip) {
// Set chained setp is used, so it can be used by formatter to o/p.
self::$chainedstepused = true;
$callresult = $result->getCallResult();
$steps = $callresult->getReturn();
if (!is_array($steps)) {
// Test it, no need to dispatch events for single chain.
$stepresult = $this->test($env, $feature, $steps, $skip);
return $this->checkSkipResult($stepresult);
}
// Test all steps.
foreach ($steps as $step) {
// Setup new step.
$event = new BeforeStepTested($env, $feature, $step);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::BEFORE);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::BEFORE, $event);
}
$setup = $this->setUp($env, $feature, $step, $skip);
$event = new AfterStepSetup($env, $feature, $step, $setup);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::AFTER_SETUP);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::AFTER_SETUP, $event);
}
// Test it.
$stepresult = $this->test($env, $feature, $step, $skip);
// Tear down.
$event = new BeforeStepTeardown($env, $feature, $step, $result);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::BEFORE_TEARDOWN);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::BEFORE_TEARDOWN, $event);
}
$teardown = $this->tearDown($env, $feature, $step, $skip, $result);
$event = new AfterStepTested($env, $feature, $step, $result, $teardown);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::AFTER);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::AFTER, $event);
}
if (!$stepresult->isPassed()) {
return $this->checkSkipResult($stepresult);
}
}
return $this->checkSkipResult($stepresult);
}
/**
* Handle skip exception.
*
* @param StepResult $result
*
* @return ExecutedStepResult|SkippedStepResult
*/
private function checkSkipResult(StepResult $result) {
if ((method_exists($result, 'getException')) && ($result->getException() instanceof SkippedException)) {
return new SkippedStepResult($result->getSearchResult());
} else {
return $result;
}
}
/**
* Returns if cahined steps are used.
* @return bool.
*/
public static function is_chained_step_used() {
return self::$chainedstepused;
}
}
@@ -0,0 +1,140 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\EventDispatcher\Tester;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
use Behat\Behat\EventDispatcher\Event\AfterStepSetup;
use Behat\Behat\EventDispatcher\Event\AfterStepTested;
use Behat\Behat\EventDispatcher\Event\BeforeStepTeardown;
use Behat\Behat\EventDispatcher\Event\BeforeStepTested;
use Behat\Behat\Tester\Result\StepResult;
use Behat\Behat\Tester\StepTester;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\StepNode;
use Behat\Testwork\Environment\Environment;
use Behat\Testwork\EventDispatcher\TestworkEventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Step tester dispatching BEFORE/AFTER events during tests.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class MoodleEventDispatchingStepTester implements StepTester {
/** @var StepTester */
private $basetester;
/** @var EventDispatcherInterface */
private $eventdispatcher;
/**
* Initializes tester.
*
* @param StepTester $basetester
* @param EventDispatcherInterface $eventdispatcher
*/
public function __construct(StepTester $basetester, EventDispatcherInterface $eventdispatcher) {
$this->basetester = $basetester;
$this->eventdispatcher = $eventdispatcher;
}
/**
* Sets up step for a test.
*
* @param Environment $env
* @param FeatureNode $feature
* @param StepNode $step
* @param bool $skip
*
* @return Setup
*/
public function setUp(Environment $env, FeatureNode $feature, StepNode $step, $skip) {
$event = new BeforeStepTested($env, $feature, $step);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::BEFORE);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::BEFORE, $event);
}
$setup = $this->basetester->setUp($env, $feature, $step, $skip);
$this->basetester->setEventDispatcher($this->eventdispatcher);
$event = new AfterStepSetup($env, $feature, $step, $setup);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::AFTER_SETUP);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::AFTER_SETUP, $event);
}
return $setup;
}
/**
* Tests step.
*
* @param Environment $env
* @param FeatureNode $feature
* @param StepNode $step
* @param bool $skip
* @return StepResult
*/
public function test(Environment $env, FeatureNode $feature, StepNode $step, $skip) {
return $this->basetester->test($env, $feature, $step, $skip);
}
/**
* Tears down step after a test.
*
* @param Environment $env
* @param FeatureNode $feature
* @param StepNode $step
* @param bool $skip
* @param StepResult $result
* @return Teardown
*/
public function tearDown(Environment $env, FeatureNode $feature, StepNode $step, $skip, StepResult $result) {
$event = new BeforeStepTeardown($env, $feature, $step, $result);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::BEFORE_TEARDOWN);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::BEFORE_TEARDOWN, $event);
}
$teardown = $this->basetester->tearDown($env, $feature, $step, $skip, $result);
$event = new AfterStepTested($env, $feature, $step, $result, $teardown);
if (TestworkEventDispatcher::DISPATCHER_VERSION === 2) {
// Symfony 4.3 and up.
$this->eventdispatcher->dispatch($event, $event::AFTER);
} else {
// TODO: Remove when our min supported version is >= 4.3.
$this->eventdispatcher->dispatch($event::AFTER, $event);
}
return $teardown;
}
}
@@ -0,0 +1,26 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Exception;
/**
* Skipped exception (throw this to mark step as "skipped").
*
* @package core
* @author Jerome Mouneyrac
*/
class SkippedException extends \Exception {
}
@@ -0,0 +1,147 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Output\Formatter;
use Behat\Behat\EventDispatcher\Event\AfterOutlineTested;
use Behat\Behat\EventDispatcher\Event\AfterScenarioTested;
use Behat\Testwork\Output\Formatter;
use Behat\Testwork\Output\Printer\OutputPrinter;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Feature step counter for distributing features between parallel runs.
*
* Use it with --dry-run (and any other selectors combination) to
* get the results quickly.
*
* @package core
* @copyright 2015 onwards Rajesh Taneja
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleListFormatter implements Formatter {
/** @var OutputPrinter */
private $printer;
/** @var array */
private $parameters;
/** @var string */
private $name;
/** @var string */
private $description;
/**
* Initializes formatter.
*
* @param string $name
* @param string $description
* @param array $parameters
* @param OutputPrinter $printer
*/
public function __construct($name, $description, array $parameters, OutputPrinter $printer) {
$this->name = $name;
$this->description = $description;
$this->parameters = $parameters;
$this->printer = $printer;
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents() {
return [
'tester.scenario_tested.after' => 'afterScenario',
'tester.outline_tested.after' => 'afterOutlineExample',
];
}
/**
* Returns formatter name.
*
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Returns formatter description.
*
* @return string
*/
public function getDescription() {
return $this->description;
}
/**
* Returns formatter output printer.
*
* @return OutputPrinter
*/
public function getOutputPrinter() {
return $this->printer;
}
/**
* Sets formatter parameter.
*
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value) {
$this->parameters[$name] = $value;
}
/**
* Returns parameter name.
*
* @param string $name
*
* @return mixed
*/
public function getParameter($name) {
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
/**
* Listens to "scenario.after" event.
*
* @param AfterScenarioTested $event
*/
public function afterScenario(AfterScenarioTested $event) {
$scenario = $event->getScenario();
$this->printer->writeln($event->getFeature()->getFile() . ':' . $scenario->getLine());
}
/**
* Listens to "outline.example.after" event.
*
* @param AfterOutlineTested $event
*/
public function afterOutlineExample(AfterOutlineTested $event) {
$outline = $event->getOutline();
$line = $outline->getLine();
$this->printer->writeln($event->getFeature()->getFile() . ':' . $line);
}
}
@@ -0,0 +1,210 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Output\Formatter;
use Behat\Testwork\Exception\ServiceContainer\ExceptionExtension;
use Behat\Testwork\Output\ServiceContainer\Formatter\FormatterFactory;
use Behat\Testwork\Output\ServiceContainer\OutputExtension;
use Behat\Testwork\ServiceContainer\ServiceProcessor;
use Behat\Testwork\Translator\ServiceContainer\TranslatorExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Moodle behat context class resolver.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleProgressFormatterFactory implements FormatterFactory {
/** @var ServiceProcessor */
private $processor;
/** @var string moodle progress ID */
const ROOT_LISTENER_ID_MOODLE = 'output.node.listener.moodleprogress';
/** @var string moodle printer ID */
const RESULT_TO_STRING_CONVERTER_ID_MOODLE = 'output.node.printer.result_to_string';
/** @var string Available extension points */
const ROOT_LISTENER_WRAPPER_TAG_MOODLE = 'output.node.listener.moodleprogress.wrapper';
/**
* Initializes extension.
*
* @param null|ServiceProcessor $processor
*/
public function __construct(ServiceProcessor $processor = null) {
$this->processor = $processor ? : new ServiceProcessor();
}
/**
* Builds formatter configuration.
*
* @param ContainerBuilder $container
*/
public function buildFormatter(ContainerBuilder $container) {
$this->loadRootNodeListener($container);
$this->loadCorePrinters($container);
$this->loadPrinterHelpers($container);
$this->loadFormatter($container);
}
/**
* Processes formatter configuration.
*
* @param ContainerBuilder $container
*/
public function processFormatter(ContainerBuilder $container) {
$this->processListenerWrappers($container);
}
/**
* Loads progress formatter node event listener.
*
* @param ContainerBuilder $container
*/
protected function loadRootNodeListener(ContainerBuilder $container) {
$definition = new Definition('Behat\Behat\Output\Node\EventListener\AST\StepListener', [
new Reference('output.node.printer.moodleprogress.step')
]);
$container->setDefinition(self::ROOT_LISTENER_ID_MOODLE, $definition);
}
/**
* Loads formatter itself.
*
* @param ContainerBuilder $container
*/
protected function loadFormatter(ContainerBuilder $container) {
$definition = new Definition('Behat\Behat\Output\Statistics\TotalStatistics');
$container->setDefinition('output.moodleprogress.statistics', $definition);
$moodleconfig = $container->getParameter('behat.moodle.parameters');
$definition = new Definition(
'Moodle\BehatExtension\Output\Printer\MoodleProgressPrinter',
[$moodleconfig['moodledirroot']]
);
$container->setDefinition('moodle.output.node.printer.moodleprogress.printer', $definition);
$definition = new Definition('Behat\Testwork\Output\NodeEventListeningFormatter', [
'moodle_progress',
'Prints information about then run followed by one character per step.',
[
'timer' => true
],
$this->createOutputPrinterDefinition(),
new Definition('Behat\Testwork\Output\Node\EventListener\ChainEventListener', [
[
new Reference(self::ROOT_LISTENER_ID_MOODLE),
new Definition('Behat\Behat\Output\Node\EventListener\Statistics\StatisticsListener', [
new Reference('output.moodleprogress.statistics'),
new Reference('output.node.printer.moodleprogress.statistics')
]),
new Definition('Behat\Behat\Output\Node\EventListener\Statistics\ScenarioStatsListener', [
new Reference('output.moodleprogress.statistics')
]),
new Definition('Behat\Behat\Output\Node\EventListener\Statistics\StepStatsListener', [
new Reference('output.moodleprogress.statistics'),
new Reference(ExceptionExtension::PRESENTER_ID)
]),
new Definition('Behat\Behat\Output\Node\EventListener\Statistics\HookStatsListener', [
new Reference('output.moodleprogress.statistics'),
new Reference(ExceptionExtension::PRESENTER_ID)
]),
new Definition('Behat\Behat\Output\Node\EventListener\AST\SuiteListener', [
new Reference('moodle.output.node.printer.moodleprogress.printer')
])
]
])
]);
$definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 1]);
$container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodleprogress', $definition);
}
/**
* Loads printer helpers.
*
* @param ContainerBuilder $container
*/
protected function loadPrinterHelpers(ContainerBuilder $container) {
$definition = new Definition('Behat\Behat\Output\Node\Printer\Helper\ResultToStringConverter');
$container->setDefinition(self::RESULT_TO_STRING_CONVERTER_ID_MOODLE, $definition);
}
/**
* Loads feature, scenario and step printers.
*
* @param ContainerBuilder $container
*/
protected function loadCorePrinters(ContainerBuilder $container) {
$definition = new Definition('Behat\Behat\Output\Node\Printer\CounterPrinter', [
new Reference(self::RESULT_TO_STRING_CONVERTER_ID_MOODLE),
new Reference(TranslatorExtension::TRANSLATOR_ID),
]);
$container->setDefinition('output.node.moodle.printer.counter', $definition);
$definition = new Definition('Behat\Behat\Output\Node\Printer\ListPrinter', [
new Reference(self::RESULT_TO_STRING_CONVERTER_ID_MOODLE),
new Reference(ExceptionExtension::PRESENTER_ID),
new Reference(TranslatorExtension::TRANSLATOR_ID),
'%paths.base%'
]);
$container->setDefinition('output.node.moodle.printer.list', $definition);
$definition = new Definition('Behat\Behat\Output\Node\Printer\Progress\ProgressStepPrinter', [
new Reference(self::RESULT_TO_STRING_CONVERTER_ID_MOODLE)
]);
$container->setDefinition('output.node.printer.moodleprogress.step', $definition);
$definition = new Definition('Behat\Behat\Output\Node\Printer\Progress\ProgressStatisticsPrinter', [
new Reference('output.node.moodle.printer.counter'),
new Reference('output.node.moodle.printer.list')
]);
$container->setDefinition('output.node.printer.moodleprogress.statistics', $definition);
}
/**
* Creates output printer definition.
*
* @return Definition
*/
protected function createOutputPrinterDefinition() {
return new Definition('Behat\Testwork\Output\Printer\StreamOutputPrinter', [
new Definition('Behat\Behat\Output\Printer\ConsoleOutputFactory'),
]);
}
/**
* Processes all registered pretty formatter node listener wrappers.
*
* @param ContainerBuilder $container
*/
protected function processListenerWrappers(ContainerBuilder $container) {
$this->processor->processWrapperServices(
$container,
self::ROOT_LISTENER_ID_MOODLE,
self::ROOT_LISTENER_WRAPPER_TAG_MOODLE
);
}
}
@@ -0,0 +1,295 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Output\Formatter;
use Behat\Behat\EventDispatcher\Event\AfterStepTested;
use Behat\Behat\EventDispatcher\Event\BeforeScenarioTested;
use Behat\Behat\EventDispatcher\Event\BeforeStepTested;
use Behat\Testwork\Output\Formatter;
use Behat\Testwork\Output\Printer\OutputPrinter;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Feature step counter for distributing features between parallel runs.
*
* Use it with --dry-run (and any other selectors combination) to
* get the results quickly.
*
* @package core
* @copyright 2016 onwards Rajesh Taneja
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleScreenshotFormatter implements Formatter {
/** @var OutputPrinter */
private $printer;
/** @var array */
private $parameters;
/** @var string */
private $name;
/** @var string */
private $description;
/** @var int The scenario count */
protected static $currentscenariocount = 0;
/** @var int The step count within the current scenario */
protected static $currentscenariostepcount = 0;
/**
* If we are saving any kind of dump on failure we should use the same parent dir during a run.
*
* @var The parent dir name
*/
protected static $faildumpdirname = false;
/**
* Initializes formatter.
*
* @param string $name
* @param string $description
* @param array $parameters
* @param OutputPrinter $printer
*/
public function __construct($name, $description, array $parameters, OutputPrinter $printer) {
$this->name = $name;
$this->description = $description;
$this->parameters = $parameters;
$this->printer = $printer;
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents() {
return [
'tester.scenario_tested.before' => 'beforeScenario',
'tester.step_tested.before' => 'beforeStep',
'tester.step_tested.after' => 'afterStep',
];
}
/**
* Returns formatter name.
*
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Returns formatter description.
*
* @return string
*/
public function getDescription() {
return $this->description;
}
/**
* Returns formatter output printer.
*
* @return OutputPrinter
*/
public function getOutputPrinter() {
return $this->printer;
}
/**
* Sets formatter parameter.
*
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value) {
$this->parameters[$name] = $value;
}
/**
* Returns parameter name.
*
* @param string $name
* @return mixed
*/
public function getParameter($name) {
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
/**
* Reset currentscenariostepcount
*
* @param BeforeScenarioTested $event
*/
public function beforeScenario(BeforeScenarioTested $event) {
self::$currentscenariostepcount = 0;
self::$currentscenariocount++;
}
/**
* Increment currentscenariostepcount
*
* @param BeforeStepTested $event
*/
public function beforeStep(BeforeStepTested $event) {
self::$currentscenariostepcount++;
}
/**
* Take screenshot after step is executed. Behat\Behat\Event\html
*
* @param AfterStepTested $event
*/
public function afterStep(AfterStepTested $event) {
$behathookcontext = $event->getEnvironment()->getContext('behat_hooks');
$formats = $this->getParameter('formats');
$formats = explode(',', $formats);
// Take screenshot.
if (in_array('image', $formats)) {
$this->take_screenshot($event, $behathookcontext);
}
// Save html content.
if (in_array('html', $formats)) {
$this->take_contentdump($event, $behathookcontext);
}
}
/**
* Return screenshot directory where all screenshots will be saved.
*
* @return string
*/
protected function get_run_screenshot_dir() {
global $CFG;
if (self::$faildumpdirname) {
return self::$faildumpdirname;
}
// If output_path is set then use output_path else use faildump_path.
if ($this->getOutputPrinter()->getOutputPath()) {
$screenshotpath = $this->getOutputPrinter()->getOutputPath();
} else if ($CFG->behat_faildump_path) {
$screenshotpath = $CFG->behat_faildump_path;
} else {
// It should never reach here.
throw new FormatterException('You should specify --out "SOME/PATH" for moodle_screenshot format');
}
if ($this->getParameter('dir_permissions')) {
$dirpermissions = $this->getParameter('dir_permissions');
} else {
$dirpermissions = 0777;
}
// All the screenshot dumps should be in the same parent dir.
self::$faildumpdirname = $screenshotpath . DIRECTORY_SEPARATOR . date('Ymd_His');
if (!is_dir(self::$faildumpdirname) && !mkdir(self::$faildumpdirname, $dirpermissions, true)) {
// It shouldn't, we already checked that the directory is writable.
throw new FormatterException(sprintf(
'No directories can be created inside %s, check the directory permissions.', $screenshotpath
));
}
return self::$faildumpdirname;
}
/**
* Take screenshot when a step fails.
*
* @throws Exception
* @param AfterStepTested $event
* @param Context $context
*/
protected function take_screenshot(AfterStepTested $event, $context) {
// BrowserKit can't save screenshots.
if ($context->getMink()->isSessionStarted($context->getMink()->getDefaultSessionName())) {
if (get_class($context->getMink()->getSession()->getDriver()) === 'Behat\Mink\Driver\BrowserKitDriver') {
return false;
}
list ($dir, $filename) = $this->get_faildump_filename($event, 'png');
$context->saveScreenshot($filename, $dir);
}
}
/**
* Take a dump of the page content when a step fails.
*
* @throws Exception
* @param AfterStepTested $event
* @param \Behat\Context\Context\Context $context
*/
protected function take_contentdump(AfterStepTested $event, $context) {
list ($dir, $filename) = $this->get_faildump_filename($event, 'html');
$fh = fopen($dir . DIRECTORY_SEPARATOR . $filename, 'w');
fwrite($fh, $context->getMink()->getSession()->getPage()->getContent());
fclose($fh);
}
/**
* Determine the full pathname to store a failure-related dump.
*
* This is used for content such as the DOM, and screenshots.
*
* @param AfterStepTested $event
* @param String $filetype The file suffix to use. Limited to 4 chars.
*/
protected function get_faildump_filename(AfterStepTested $event, $filetype) {
// Make a directory for the scenario.
$featurename = $event->getFeature()->getTitle();
$featurename = preg_replace('/([^a-zA-Z0-9\_]+)/', '-', $featurename);
if ($this->getParameter('dir_permissions')) {
$dirpermissions = $this->getParameter('dir_permissions');
} else {
$dirpermissions = 0777;
}
$dir = $this->get_run_screenshot_dir();
// We want a i-am-the-scenario-title format.
$dir = $dir . DIRECTORY_SEPARATOR . self::$currentscenariocount . '-' . $featurename;
if (!is_dir($dir) && !mkdir($dir, $dirpermissions, true)) {
// We already checked that the directory is writable. This should not fail.
throw new FormatterException(sprintf(
'No directories can be created inside %s, check the directory permissions.', $dir
));
}
// The failed step text.
// We want a stepno-i-am-the-failed-step.$filetype format.
$filename = $event->getStep()->getText();
$filename = preg_replace('/([^a-zA-Z0-9\_]+)/', '-', $filename);
$filename = self::$currentscenariostepcount . '-' . $filename;
// File name limited to 255 characters. Leaving 4 chars for the file
// extension as we allow .png for images and .html for DOM contents.
$filename = substr($filename, 0, 250) . '.' . $filetype;
return [$dir, $filename];
}
}
@@ -0,0 +1,155 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Output\Formatter;
use Behat\Behat\EventDispatcher\Event\AfterFeatureTested;
use Behat\Behat\EventDispatcher\Event\AfterStepTested;
use Behat\Behat\EventDispatcher\Event\BeforeFeatureTested;
use Behat\Testwork\Output\Formatter;
use Behat\Testwork\Output\Printer\OutputPrinter;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Feature step counter for distributing features between parallel runs.
*
* Use it with --dry-run (and any other selectors combination) to
* get the results quickly.
*
* @package core
* @copyright 2016 onwards Rajesh Taneja
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleStepcountFormatter implements Formatter {
/** @var int Number of steps executed in feature file. */
private static $stepcount = 0;
/** @var OutputPrinter */
private $printer;
/** @var array */
private $parameters;
/** @var string */
private $name;
/** @var string */
private $description;
/**
* Initializes formatter.
*
* @param string $name
* @param string $description
* @param array $parameters
* @param OutputPrinter $printer
*/
public function __construct($name, $description, array $parameters, OutputPrinter $printer) {
$this->name = $name;
$this->description = $description;
$this->parameters = $parameters;
$this->printer = $printer;
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents() {
return [
'tester.feature_tested.before' => 'beforeFeature',
'tester.feature_tested.after' => 'afterFeature',
'tester.step_tested.after' => 'afterStep',
];
}
/**
* Returns formatter name.
*
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Returns formatter description.
*
* @return string
*/
public function getDescription() {
return $this->description;
}
/**
* Returns formatter output printer.
*
* @return OutputPrinter
*/
public function getOutputPrinter() {
return $this->printer;
}
/**
* Sets formatter parameter.
*
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value) {
$this->parameters[$name] = $value;
}
/**
* Returns parameter name.
*
* @param string $name
* @return mixed
*/
public function getParameter($name) {
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
/**
* Listens to "feature.before" event.
*
* @param BeforeFeatureTested $event
*/
public function beforeFeature(BeforeFeatureTested $event) {
self::$stepcount = 0;
}
/**
* Listens to "feature.after" event.
*
* @param AfterFeatureTested $event
*/
public function afterFeature(AfterFeatureTested $event) {
$this->printer->writeln($event->getFeature()->getFile() . '::' . self::$stepcount);
}
/**
* Listens to "step.after" event.
*
* @param AfterStepTested $event
*/
public function afterStep(AfterStepTested $event) {
self::$stepcount++;
}
}
@@ -0,0 +1,133 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\Output\Printer;
use Behat\Behat\Output\Node\Printer\SetupPrinter;
use Behat\Testwork\Call\CallResult;
use Behat\Testwork\Hook\Tester\Setup\HookedTeardown;
use Behat\Testwork\Output\Formatter;
use Behat\Testwork\Output\Printer\OutputPrinter;
use Behat\Testwork\Tester\Setup\Setup;
use Behat\Testwork\Tester\Setup\Teardown;
use Moodle\BehatExtension\Driver\WebDriver;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Prints hooks in a pretty fashion.
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class MoodleProgressPrinter implements SetupPrinter {
/**
* @var string Moodle directory root.
*/
private $moodledirroot;
/**
* @var bool true if output is displayed.
*/
private static $outputdisplayed;
/**
* Constructor.
*
* @param string $moodledirroot Moodle dir root.
*/
public function __construct($moodledirroot) {
$this->moodledirroot = $moodledirroot;
}
/**
* Prints setup state.
*
* @param Formatter $formatter
* @param Setup $setup
*/
public function printSetup(Formatter $formatter, Setup $setup) {
if (empty(self::$outputdisplayed)) {
$this->printMoodleInfo($formatter->getOutputPrinter());
self::$outputdisplayed = true;
}
}
/**
* Prints teardown state.
*
* @param Formatter $formatter
* @param Teardown $teardown
*/
public function printTeardown(Formatter $formatter, Teardown $teardown) {
if (!$teardown instanceof HookedTeardown) {
return;
}
foreach ($teardown->getHookCallResults() as $callresult) {
$this->printTeardownHookCallResult($formatter->getOutputPrinter(), $callresult);
}
}
/**
* We print the site info + driver used and OS.
*
* @param Printer $printer
* @return void
*/
public function printMoodleInfo($printer) {
require_once($this->moodledirroot . '/lib/behat/classes/util.php');
$browser = WebDriver::getBrowserName();
// Calling all directly from here as we avoid more behat framework extensions.
$runinfo = \behat_util::get_site_info();
$runinfo .= 'Server OS "' . PHP_OS . '"' . ', Browser: "' . $browser . '"' . PHP_EOL;
$runinfo .= 'Started at ' . date('d-m-Y, H:i', time());
$printer->writeln($runinfo);
}
/**
* Prints teardown hook call result.
*
* @param OutputPrinter $printer
* @param CallResult $callresult
*/
private function printTeardownHookCallResult(OutputPrinter $printer, CallResult $callresult) {
// Notify dev that chained step is being used.
if (\Moodle\BehatExtension\EventDispatcher\Tester\ChainedStepTester::is_chained_step_used()) {
$printer->writeln();
$printer->write(
"{+failed}Chained steps are deprecated. " .
"See https://moodledev.io/general/development/tools/behat/" .
"Migrating_from_Behat_2.5_to_3.x_in_Moodle#Changes_required_in_context_file{-failed}"
);
}
if (!$callresult->hasStdOut() && !$callresult->hasException()) {
return;
}
$hook = $callresult->getCall()->getCallee();
$path = $hook->getPath();
$printer->writeln($hook);
$printer->writeln($path);
}
}
@@ -0,0 +1,289 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace Moodle\BehatExtension\ServiceContainer;
use Behat\Behat\Definition\ServiceContainer\DefinitionExtension;
use Behat\Behat\EventDispatcher\ServiceContainer\EventDispatcherExtension;
use Behat\Behat\Gherkin\ServiceContainer\GherkinExtension;
use Behat\Behat\Tester\ServiceContainer\TesterExtension;
use Behat\Testwork\Cli\ServiceContainer\CliExtension;
use Behat\Testwork\Output\ServiceContainer\OutputExtension;
use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface;
use Behat\Testwork\ServiceContainer\ExtensionManager;
use Behat\Testwork\ServiceContainer\ServiceProcessor;
use Behat\Testwork\Suite\ServiceContainer\SuiteExtension;
use Moodle\BehatExtension\Driver\WebDriverFactory;
use Moodle\BehatExtension\Output\Formatter\MoodleProgressFormatterFactory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
/**
* Behat extension for moodle
*
* Provides multiple features directory loading (Gherkin\Loader\MoodleFeaturesSuiteLoader
*
* @package core
* @copyright 2016 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class BehatExtension implements ExtensionInterface {
/** @var string Extension configuration ID */
const MOODLE_ID = 'moodle';
/** @var ServiceProcessor */
private $processor;
/**
* Initializes compiler pass.
*
* @param null|ServiceProcessor $processor
*/
public function __construct(ServiceProcessor $processor = null) {
$this->processor = $processor ? : new ServiceProcessor();
}
/**
* Loads moodle specific configuration.
*
* @param ContainerBuilder $container ContainerBuilder instance
* @param array $config Extension configuration hash (from behat.yml)
*/
public function load(ContainerBuilder $container, array $config) {
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/services'));
$loader->load('core.xml');
// Getting the extension parameters.
$container->setParameter('behat.moodle.parameters', $config);
// Load moodle progress formatter.
$moodleprogressformatter = new MoodleProgressFormatterFactory();
$moodleprogressformatter->buildFormatter($container);
// Load custom step tester event dispatcher.
$this->loadEventDispatchingStepTester($container);
// Load chained step tester.
$this->loadChainedStepTester($container);
// Load step count formatter.
$this->loadMoodleListFormatter($container);
// Load step count formatter.
$this->loadMoodleStepcountFormatter($container);
// Load screenshot formatter.
$this->loadMoodleScreenshotFormatter($container);
// Load namespace alias.
$this->alias_old_namespaces();
}
/**
* Loads moodle List formatter.
*
* @param ContainerBuilder $container
*/
protected function loadMoodleListFormatter(ContainerBuilder $container) {
$definition = new Definition('Moodle\BehatExtension\Output\Formatter\MoodleListFormatter', [
'moodle_list',
'List all scenarios. Use with --dry-run',
['stepcount' => false],
$this->createOutputPrinterDefinition()
]);
$definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 101]);
$container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodle_list', $definition);
}
/**
* Loads moodle Step count formatter.
*
* @param ContainerBuilder $container
*/
protected function loadMoodleStepcountFormatter(ContainerBuilder $container) {
$definition = new Definition('Moodle\BehatExtension\Output\Formatter\MoodleStepcountFormatter', [
'moodle_stepcount',
'Count steps in feature files. Use with --dry-run',
['stepcount' => false],
$this->createOutputPrinterDefinition()
]);
$definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 101]);
$container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodle_stepcount', $definition);
}
/**
* Loads moodle screenshot formatter.
*
* @param ContainerBuilder $container
*/
protected function loadMoodleScreenshotFormatter(ContainerBuilder $container) {
$definition = new Definition('Moodle\BehatExtension\Output\Formatter\MoodleScreenshotFormatter', [
'moodle_screenshot',
// phpcs:ignore Generic.Files.LineLength.TooLong
'Take screenshot of all steps. Use --format-settings \'{"formats": "html,image"}\' to get specific o/p type',
['formats' => 'html,image'],
$this->createOutputPrinterDefinition()
]);
$definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 102]);
$container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodle_screenshot', $definition);
}
/**
* Creates output printer definition.
*
* @return Definition
*/
protected function createOutputPrinterDefinition() {
return new Definition('Behat\Testwork\Output\Printer\StreamOutputPrinter', [
new Definition('Behat\Behat\Output\Printer\ConsoleOutputFactory'),
]);
}
/**
* Loads definition printers.
*
* @param ContainerBuilder $container
*/
private function loadDefinitionPrinters(ContainerBuilder $container) {
$definition = new Definition('Moodle\BehatExtension\Definition\Printer\ConsoleDefinitionInformationPrinter', [
new Reference(CliExtension::OUTPUT_ID),
new Reference(DefinitionExtension::PATTERN_TRANSFORMER_ID),
new Reference(DefinitionExtension::DEFINITION_TRANSLATOR_ID),
new Reference(GherkinExtension::KEYWORDS_ID)
]);
$container->removeDefinition('definition.information_printer');
$container->setDefinition('definition.information_printer', $definition);
}
/**
* Loads definition controller.
*
* @param ContainerBuilder $container
*/
private function loadController(ContainerBuilder $container) {
$definition = new Definition('Moodle\BehatExtension\Definition\Cli\AvailableDefinitionsController', [
new Reference(SuiteExtension::REGISTRY_ID),
new Reference(DefinitionExtension::WRITER_ID),
new Reference('definition.list_printer'),
new Reference('definition.information_printer')
]);
$container->removeDefinition(CliExtension::CONTROLLER_TAG . '.available_definitions');
$container->setDefinition(CliExtension::CONTROLLER_TAG . '.available_definitions', $definition);
}
/**
* Loads chained step tester.
*
* @param ContainerBuilder $container
*/
protected function loadChainedStepTester(ContainerBuilder $container) {
// Chained steps.
$definition = new Definition('Moodle\BehatExtension\EventDispatcher\Tester\ChainedStepTester', [
new Reference(TesterExtension::STEP_TESTER_ID),
]);
$definition->addTag(TesterExtension::STEP_TESTER_WRAPPER_TAG, ['priority' => 100]);
$container->setDefinition(TesterExtension::STEP_TESTER_WRAPPER_TAG . '.substep', $definition);
}
/**
* Loads event-dispatching step tester.
*
* @param ContainerBuilder $container
*/
protected function loadEventDispatchingStepTester(ContainerBuilder $container) {
$definition = new Definition('Moodle\BehatExtension\EventDispatcher\Tester\MoodleEventDispatchingStepTester', [
new Reference(TesterExtension::STEP_TESTER_ID),
new Reference(EventDispatcherExtension::DISPATCHER_ID)
]);
$definition->addTag(TesterExtension::STEP_TESTER_WRAPPER_TAG, ['priority' => -9999]);
$container->setDefinition(TesterExtension::STEP_TESTER_WRAPPER_TAG . '.event_dispatching', $definition);
}
/**
* Setups configuration for current extension.
*
* @param ArrayNodeDefinition $builder
*/
public function configure(ArrayNodeDefinition $builder) {
// phpcs:disable PEAR.WhiteSpace.ObjectOperatorIndent.Incorrect
$builder->children()
->arrayNode('capabilities')
->useAttributeAsKey('key')
->prototype('variable')->end()
->end()
->arrayNode('steps_definitions')
->useAttributeAsKey('key')
->prototype('variable')->end()
->end()
->scalarNode('moodledirroot')
->defaultNull()
->end()
->end()
->end();
// phpcs:enable PEAR.WhiteSpace.ObjectOperatorIndent.Incorrect
}
/**
* Returns the extension config key.
*
* @return string
*/
public function getConfigKey() {
return self::MOODLE_ID;
}
/**
* Initializes other extensions.
*
* This method is called immediately after all extensions are activated but
* before any extension `configure()` method is called. This allows extensions
* to hook into the configuration of other extensions providing such an
* extension point.
*
* @param ExtensionManager $extensionmanager
*/
public function initialize(ExtensionManager $extensionmanager) {
if (null !== $minkextension = $extensionmanager->getExtension('mink')) {
$minkextension->registerDriverFactory(new WebDriverFactory());
}
}
/**
* You can modify the container here before it is dumped to PHP code.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container) {
// Load controller for definition printing.
$this->loadDefinitionPrinters($container);
$this->loadController($container);
}
/**
* Alias old namespace of given. when and then for BC.
*/
private function alias_old_namespaces() {
class_alias('Moodle\\BehatExtension\\Context\\Step\\Given', 'Behat\\Behat\\Context\\Step\\Given', true);
class_alias('Moodle\\BehatExtension\\Context\\Step\\When', 'Behat\\Behat\\Context\\Step\\When', true);
class_alias('Moodle\\BehatExtension\\Context\\Step\\Then', 'Behat\\Behat\\Context\\Step\\Then', true);
}
}
@@ -0,0 +1,26 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="behat.moodle.parameters"></parameter>
<parameter key="moodle.context.initializer.class">Moodle\BehatExtension\Context\Initializer\MoodleAwareInitializer</parameter>
<parameter key="moodle.context.contextclass.classresolver.class">Moodle\BehatExtension\Context\ContextClass\ClassResolver</parameter>
<parameter key="behat.mink.selector.handler.class">Behat\Mink\Selector\SelectorsHandler</parameter>
</parameters>
<services>
<!-- Moodle context initializer -->
<service id="moodle.context.initializer" class="%moodle.context.initializer.class%">
<argument>%behat.moodle.parameters%</argument>
<tag name="context.initializer" />
</service>
<!-- Moodle class resolver for behat context -->
<service id="moodle.context.contextclass.classresolver" class="%moodle.context.contextclass.classresolver.class%">
<argument>%behat.moodle.parameters%</argument>
<tag name="context.class_resolver" />
</service>
</services>
</container>