See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace Moodle\BehatExtension\ServiceContainer; 18 19 use Behat\Behat\Definition\ServiceContainer\DefinitionExtension; 20 use Behat\Behat\EventDispatcher\ServiceContainer\EventDispatcherExtension; 21 use Behat\Behat\Gherkin\ServiceContainer\GherkinExtension; 22 use Behat\Behat\Tester\ServiceContainer\TesterExtension; 23 use Behat\Testwork\Cli\ServiceContainer\CliExtension; 24 use Behat\Testwork\Output\ServiceContainer\OutputExtension; 25 use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface; 26 use Behat\Testwork\ServiceContainer\ExtensionManager; 27 use Behat\Testwork\ServiceContainer\ServiceProcessor; 28 use Behat\Testwork\Specification\ServiceContainer\SpecificationExtension; 29 use Behat\Testwork\Suite\ServiceContainer\SuiteExtension; 30 use Moodle\BehatExtension\Driver\WebDriverFactory; 31 use Moodle\BehatExtension\Output\Formatter\MoodleProgressFormatterFactory; 32 use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; 33 use Symfony\Component\Config\FileLocator; 34 use Symfony\Component\DependencyInjection\ContainerBuilder; 35 use Symfony\Component\DependencyInjection\Definition; 36 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; 37 use Symfony\Component\DependencyInjection\Reference; 38 39 // phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod 40 41 /** 42 * Behat extension for moodle 43 * 44 * Provides multiple features directory loading (Gherkin\Loader\MoodleFeaturesSuiteLoader 45 * 46 * @package core 47 * @copyright 2016 Rajesh Taneja <rajesh@moodle.com> 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 */ 50 class BehatExtension implements ExtensionInterface { 51 /** @var string Extension configuration ID */ 52 const MOODLE_ID = 'moodle'; 53 54 /** @var string Gherkin ID */ 55 const GHERKIN_ID = 'gherkin'; 56 57 /** @var ServiceProcessor */ 58 private $processor; 59 60 /** 61 * Initializes compiler pass. 62 * 63 * @param null|ServiceProcessor $processor 64 */ 65 public function __construct(ServiceProcessor $processor = null) { 66 $this->processor = $processor ? : new ServiceProcessor(); 67 } 68 69 /** 70 * Loads moodle specific configuration. 71 * 72 * @param ContainerBuilder $container ContainerBuilder instance 73 * @param array $config Extension configuration hash (from behat.yml) 74 */ 75 public function load(ContainerBuilder $container, array $config) { 76 $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/services')); 77 $loader->load('core.xml'); 78 79 // Getting the extension parameters. 80 $container->setParameter('behat.moodle.parameters', $config); 81 82 // Load moodle progress formatter. 83 $moodleprogressformatter = new MoodleProgressFormatterFactory(); 84 $moodleprogressformatter->buildFormatter($container); 85 86 // Load custom step tester event dispatcher. 87 $this->loadEventDispatchingStepTester($container); 88 89 // Load chained step tester. 90 $this->loadChainedStepTester($container); 91 92 // Load step count formatter. 93 $this->loadMoodleListFormatter($container); 94 95 // Load step count formatter. 96 $this->loadMoodleStepcountFormatter($container); 97 98 // Load screenshot formatter. 99 $this->loadMoodleScreenshotFormatter($container); 100 101 // Load namespace alias. 102 $this->alias_old_namespaces(); 103 104 // Load skip passed controller and list locator. 105 $this->loadSkipPassedController($container, $config['passed_cache']); 106 $this->loadFilesystemSkipPassedScenariosListLocator($container); 107 } 108 109 /** 110 * Loads moodle List formatter. 111 * 112 * @param ContainerBuilder $container 113 */ 114 protected function loadMoodleListFormatter(ContainerBuilder $container) { 115 $definition = new Definition('Moodle\BehatExtension\Output\Formatter\MoodleListFormatter', [ 116 'moodle_list', 117 'List all scenarios. Use with --dry-run', 118 ['stepcount' => false], 119 $this->createOutputPrinterDefinition() 120 ]); 121 $definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 101]); 122 $container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodle_list', $definition); 123 } 124 125 /** 126 * Loads moodle Step count formatter. 127 * 128 * @param ContainerBuilder $container 129 */ 130 protected function loadMoodleStepcountFormatter(ContainerBuilder $container) { 131 $definition = new Definition('Moodle\BehatExtension\Output\Formatter\MoodleStepcountFormatter', [ 132 'moodle_stepcount', 133 'Count steps in feature files. Use with --dry-run', 134 ['stepcount' => false], 135 $this->createOutputPrinterDefinition() 136 ]); 137 $definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 101]); 138 $container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodle_stepcount', $definition); 139 } 140 141 /** 142 * Loads moodle screenshot formatter. 143 * 144 * @param ContainerBuilder $container 145 */ 146 protected function loadMoodleScreenshotFormatter(ContainerBuilder $container) { 147 $definition = new Definition('Moodle\BehatExtension\Output\Formatter\MoodleScreenshotFormatter', [ 148 'moodle_screenshot', 149 // phpcs:ignore Generic.Files.LineLength.TooLong 150 'Take screenshot of all steps. Use --format-settings \'{"formats": "html,image"}\' to get specific o/p type', 151 ['formats' => 'html,image'], 152 $this->createOutputPrinterDefinition() 153 ]); 154 $definition->addTag(OutputExtension::FORMATTER_TAG, ['priority' => 102]); 155 $container->setDefinition(OutputExtension::FORMATTER_TAG . '.moodle_screenshot', $definition); 156 } 157 158 /** 159 * Creates output printer definition. 160 * 161 * @return Definition 162 */ 163 protected function createOutputPrinterDefinition() { 164 return new Definition('Behat\Testwork\Output\Printer\StreamOutputPrinter', [ 165 new Definition('Behat\Behat\Output\Printer\ConsoleOutputFactory'), 166 ]); 167 } 168 169 /** 170 * Loads skip passed controller. 171 * 172 * @param ContainerBuilder $container 173 * @param null|string $cachepath 174 */ 175 protected function loadSkipPassedController(ContainerBuilder $container, $cachepath) { 176 $definition = new Definition('Moodle\BehatExtension\Tester\Cli\SkipPassedController', [ 177 new Reference(EventDispatcherExtension::DISPATCHER_ID), 178 $cachepath, 179 $container->getParameter('paths.base') 180 ]); 181 $definition->addTag(CliExtension::CONTROLLER_TAG, ['priority' => 200]); 182 $container->setDefinition(CliExtension::CONTROLLER_TAG . '.passed', $definition); 183 } 184 185 /** 186 * Loads filesystem passed scenarios list locator. 187 * 188 * @param ContainerBuilder $container 189 */ 190 private function loadFilesystemSkipPassedScenariosListLocator(ContainerBuilder $container) { 191 $definition = new Definition('Moodle\BehatExtension\Locator\FilesystemSkipPassedListLocator', [ 192 new Reference(self::GHERKIN_ID) 193 ]); 194 $definition->addTag(SpecificationExtension::LOCATOR_TAG, ['priority' => 50]); 195 $container->setDefinition( 196 SpecificationExtension::LOCATOR_TAG . '.filesystem_skip_passed_scenarios_list', 197 $definition 198 ); 199 } 200 201 /** 202 * Loads definition printers. 203 * 204 * @param ContainerBuilder $container 205 */ 206 private function loadDefinitionPrinters(ContainerBuilder $container) { 207 $definition = new Definition('Moodle\BehatExtension\Definition\Printer\ConsoleDefinitionInformationPrinter', [ 208 new Reference(CliExtension::OUTPUT_ID), 209 new Reference(DefinitionExtension::PATTERN_TRANSFORMER_ID), 210 new Reference(DefinitionExtension::DEFINITION_TRANSLATOR_ID), 211 new Reference(GherkinExtension::KEYWORDS_ID) 212 ]); 213 $container->removeDefinition('definition.information_printer'); 214 $container->setDefinition('definition.information_printer', $definition); 215 } 216 217 /** 218 * Loads definition controller. 219 * 220 * @param ContainerBuilder $container 221 */ 222 private function loadController(ContainerBuilder $container) { 223 $definition = new Definition('Moodle\BehatExtension\Definition\Cli\AvailableDefinitionsController', [ 224 new Reference(SuiteExtension::REGISTRY_ID), 225 new Reference(DefinitionExtension::WRITER_ID), 226 new Reference('definition.list_printer'), 227 new Reference('definition.information_printer') 228 ]); 229 $container->removeDefinition(CliExtension::CONTROLLER_TAG . '.available_definitions'); 230 $container->setDefinition(CliExtension::CONTROLLER_TAG . '.available_definitions', $definition); 231 } 232 233 /** 234 * Loads chained step tester. 235 * 236 * @param ContainerBuilder $container 237 */ 238 protected function loadChainedStepTester(ContainerBuilder $container) { 239 // Chained steps. 240 $definition = new Definition('Moodle\BehatExtension\EventDispatcher\Tester\ChainedStepTester', [ 241 new Reference(TesterExtension::STEP_TESTER_ID), 242 ]); 243 $definition->addTag(TesterExtension::STEP_TESTER_WRAPPER_TAG, ['priority' => 100]); 244 $container->setDefinition(TesterExtension::STEP_TESTER_WRAPPER_TAG . '.substep', $definition); 245 } 246 247 /** 248 * Loads event-dispatching step tester. 249 * 250 * @param ContainerBuilder $container 251 */ 252 protected function loadEventDispatchingStepTester(ContainerBuilder $container) { 253 $definition = new Definition('Moodle\BehatExtension\EventDispatcher\Tester\MoodleEventDispatchingStepTester', [ 254 new Reference(TesterExtension::STEP_TESTER_ID), 255 new Reference(EventDispatcherExtension::DISPATCHER_ID) 256 ]); 257 $definition->addTag(TesterExtension::STEP_TESTER_WRAPPER_TAG, ['priority' => -9999]); 258 $container->setDefinition(TesterExtension::STEP_TESTER_WRAPPER_TAG . '.event_dispatching', $definition); 259 } 260 261 /** 262 * Setups configuration for current extension. 263 * 264 * @param ArrayNodeDefinition $builder 265 */ 266 public function configure(ArrayNodeDefinition $builder) { 267 // phpcs:disable PEAR.WhiteSpace.ObjectOperatorIndent.Incorrect 268 $builder->children() 269 ->arrayNode('capabilities') 270 ->useAttributeAsKey('key') 271 ->prototype('variable')->end() 272 ->end() 273 ->arrayNode('steps_definitions') 274 ->useAttributeAsKey('key') 275 ->prototype('variable')->end() 276 ->end() 277 ->scalarNode('moodledirroot') 278 ->defaultNull() 279 ->end() 280 ->scalarNode('passed_cache') 281 ->info('Sets the passed cache path') 282 ->defaultValue( 283 is_writable(sys_get_temp_dir()) 284 ? sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat_passed_cache' 285 : null 286 ) 287 ->end() 288 ->end() 289 ->end(); 290 // phpcs:enable PEAR.WhiteSpace.ObjectOperatorIndent.Incorrect 291 } 292 293 /** 294 * Returns the extension config key. 295 * 296 * @return string 297 */ 298 public function getConfigKey() { 299 return self::MOODLE_ID; 300 } 301 302 /** 303 * Initializes other extensions. 304 * 305 * This method is called immediately after all extensions are activated but 306 * before any extension `configure()` method is called. This allows extensions 307 * to hook into the configuration of other extensions providing such an 308 * extension point. 309 * 310 * @param ExtensionManager $extensionmanager 311 */ 312 public function initialize(ExtensionManager $extensionmanager) { 313 if (null !== $minkextension = $extensionmanager->getExtension('mink')) { 314 $minkextension->registerDriverFactory(new WebDriverFactory()); 315 } 316 } 317 318 /** 319 * You can modify the container here before it is dumped to PHP code. 320 * 321 * @param ContainerBuilder $container 322 */ 323 public function process(ContainerBuilder $container) { 324 // Load controller for definition printing. 325 $this->loadDefinitionPrinters($container); 326 $this->loadController($container); 327 } 328 329 /** 330 * Alias old namespace of given. when and then for BC. 331 */ 332 private function alias_old_namespaces() { 333 class_alias('Moodle\\BehatExtension\\Context\\Step\\Given', 'Behat\\Behat\\Context\\Step\\Given', true); 334 class_alias('Moodle\\BehatExtension\\Context\\Step\\When', 'Behat\\Behat\\Context\\Step\\When', true); 335 class_alias('Moodle\\BehatExtension\\Context\\Step\\Then', 'Behat\\Behat\\Context\\Step\\Then', true); 336 } 337 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body