container = $container; $this->registry = $registry; $this->suiteConfigurations = $container->getParameter('suite.configurations'); } /** * Configures command to be able to process it later. * * @param Command $command */ public function configure(Command $command) { $command->addArgument( 'module', InputArgument::OPTIONAL, "Specific module suite to load. " . "Must be in @modulename format. Supports @vendor/name syntax for vendor installed modules. " . "Ensure that a modulename/behat.yml exists containing a behat suite of the same name." ); $command->addOption( '--suite', '-s', InputOption::VALUE_REQUIRED, 'Only execute a specific suite.' ); } /** * Processes data from container and console input. * * @param InputInterface $input * @param OutputInterface $output * @throws RuntimeException * @return null */ public function execute(InputInterface $input, OutputInterface $output) { // Register all suites if no arguments given if (!$input->getArgument('module') && !$input->getOption('suite')) { foreach ($this->suiteConfigurations as $name => $config) { $this->registry->registerSuiteConfiguration( $name, $config['type'], $config['settings'] ); } return null; } // Don't register config if init if ($input->getOption('init')) { return; } // Get module either via @module or --suite module if ($input->getArgument('module')) { // Get suite from module $moduleName = $input->getArgument('module'); $module = $this->getModule($moduleName); // Suite name always omits vendor $suiteName = $module->getShortName(); } else { // Get module from suite $suiteName = $input->getOption('suite'); $module = $this->getModule($suiteName, false); } // Load registered suite if (isset($this->suiteConfigurations[$suiteName])) { $config = $this->suiteConfigurations[$suiteName]; } elseif ($module) { // Suite doesn't exist, so load dynamically from nested `behat.yml` $config = $this->loadSuiteConfiguration($suiteName, $module); } else { throw new InvalidArgumentException("Could not find suite config {$suiteName}"); } // Register config $this->registry->registerSuiteConfiguration( $suiteName, $config['type'], $config['settings'] ); return null; } /** * Get behat.yml configured for this module * * @param Module $module * @return string Path to config */ protected function findModuleConfig(Module $module) { $pathSuffix = $this->container->getParameter('silverstripe_extension.context.features_path'); $path = $module->getPath(); // Find all candidate paths foreach ([ "{$path}/", "{$path}/{$pathSuffix}"] as $parent) { foreach ([$parent.'behat.yml', $parent.'.behat.yml'] as $candidate) { if (file_exists($candidate ?? '')) { return $candidate; } } } throw new InvalidArgumentException("No behat.yml found for module " . $module->getName()); } /** * Load configuration dynamically from yml * * @param string $suite Suite name * @param Module $module * @return array * @throws Exception */ protected function loadSuiteConfiguration($suite, Module $module) { $path = $this->findModuleConfig($module); $yamlParser = new Parser(); $config = $yamlParser->parse(file_get_contents($path ?? '')); if (empty($config['default']['suites'][$suite])) { throw new Exception("Path {$path} does not contain default.suites.{$suite} config"); } $suiteConfig = $config['default']['suites'][$suite]; // Resolve variables $resolvedConfig = $this->container->getParameterBag()->resolveValue($suiteConfig); return [ 'type' => null, // @todo figure out what this is for 'settings' => $resolvedConfig, ]; } }