mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 00:46:50 +02:00
MDL-58428 behat: Check parent themes for Behat override steps.
Behat will now look at the current themes' parents for Behat ovveride steps. If found we will use the steps replacing the Moodle core steps.
This commit is contained in:
parent
e3652936f3
commit
4aefaf653b
10 changed files with 110 additions and 131 deletions
|
@ -55,11 +55,6 @@ class behat_config_util {
|
|||
*/
|
||||
private $themecontexts;
|
||||
|
||||
/**
|
||||
* @var array list of all contexts in theme suite.
|
||||
*/
|
||||
private $themesuitecontexts;
|
||||
|
||||
/**
|
||||
* @var array list of overridden theme contexts.
|
||||
*/
|
||||
|
@ -314,13 +309,16 @@ class behat_config_util {
|
|||
|
||||
$this->contexts = array();
|
||||
foreach ($components as $componentname => $componentpath) {
|
||||
if (false !== strpos($componentname, 'theme_')) {
|
||||
continue;
|
||||
}
|
||||
$componentpath = self::clean_path($componentpath);
|
||||
|
||||
if (!file_exists($componentpath . self::get_behat_tests_path())) {
|
||||
continue;
|
||||
}
|
||||
$diriterator = new DirectoryIterator($componentpath . self::get_behat_tests_path());
|
||||
$regite = new RegexIterator($diriterator, '|behat_.*\.php$|');
|
||||
$regite = new RegexIterator($diriterator, '|^behat_.*\.php$|');
|
||||
|
||||
// All behat_*.php inside self::get_behat_tests_path() are added as steps definitions files.
|
||||
foreach ($regite as $file) {
|
||||
|
@ -493,24 +491,23 @@ class behat_config_util {
|
|||
|
||||
$suites = $this->get_behat_suites($parallelruns, $currentrun);
|
||||
|
||||
$overriddenthemescontexts = $this->get_overridden_theme_contexts();
|
||||
if (!empty($overriddenthemescontexts)) {
|
||||
$allcontexts = array_merge($this->contexts, $overriddenthemescontexts);
|
||||
} else {
|
||||
$allcontexts = $this->contexts;
|
||||
}
|
||||
|
||||
// Remove selectors from step definitions.
|
||||
$themes = $this->get_list_of_themes();
|
||||
$selectortypes = ['named_partial', 'named_exact'];
|
||||
foreach ($themes as $theme) {
|
||||
$allpaths = [];
|
||||
foreach (array_keys($suites) as $theme) {
|
||||
// Remove selectors from step definitions.
|
||||
foreach ($selectortypes as $selectortype) {
|
||||
// Don't include selector classes.
|
||||
$selectorclass = self::get_behat_theme_selector_override_classname($theme, $selectortype);
|
||||
if (isset($allcontexts[$selectorclass])) {
|
||||
unset($allcontexts[$selectorclass]);
|
||||
if (isset($suites[$theme]['contexts'][$selectorclass])) {
|
||||
unset($suites[$theme]['contexts'][$selectorclass]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of all step definition paths.
|
||||
$allpaths = array_merge($allpaths, $suites[$theme]['contexts']);
|
||||
|
||||
// Convert the contexts array to a list of names only.
|
||||
$suites[$theme]['contexts'] = array_keys($suites[$theme]['contexts']);
|
||||
}
|
||||
|
||||
// Comments use black color, so failure path is not visible. Using color other then black/white is safer.
|
||||
|
@ -532,7 +529,7 @@ class behat_config_util {
|
|||
),
|
||||
'Moodle\BehatExtension' => array(
|
||||
'moodledirroot' => $CFG->dirroot,
|
||||
'steps_definitions' => $allcontexts,
|
||||
'steps_definitions' => $allpaths,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -1128,9 +1125,8 @@ class behat_config_util {
|
|||
|
||||
// Create list of theme suite features and contexts.
|
||||
foreach ($themes as $theme) {
|
||||
// Get theme features.
|
||||
// Get theme features and contexts.
|
||||
$themefeatures[$theme] = $this->get_behat_features_for_theme($theme);
|
||||
|
||||
$themecontexts[$theme] = $this->get_behat_contexts_for_theme($theme);
|
||||
}
|
||||
|
||||
|
@ -1141,20 +1137,6 @@ class behat_config_util {
|
|||
}
|
||||
}
|
||||
|
||||
// Remove list of theme contexts form other suite contexts, as suite don't require other theme specific contexts.
|
||||
foreach ($themecontexts as $themename => $themecontext) {
|
||||
if (!empty($themecontext['contexts'])) {
|
||||
foreach ($themecontext['contexts'] as $contextkey => $contextpath) {
|
||||
// Remove theme specific contexts from other themes.
|
||||
foreach ($themes as $currenttheme) {
|
||||
if (($currenttheme != $themename) && isset($themecontexts[$currenttheme]['suitecontexts'][$contextkey])) {
|
||||
unset($themecontexts[$currenttheme]['suitecontexts'][$contextkey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set suite for each theme.
|
||||
$suites = array();
|
||||
foreach ($themes as $theme) {
|
||||
|
@ -1186,12 +1168,12 @@ class behat_config_util {
|
|||
$suitename = $theme;
|
||||
}
|
||||
|
||||
// Add suite no matter what. If there is no feature in suite then it will just exist successfully with no
|
||||
// scenarios. But if we don't set this then the user has to know which run doesn't have suite and which run do.
|
||||
// Add suite no matter what. If there is no feature in suite then it will just exist successfully with no scenarios.
|
||||
// But if we don't set this then the user has to know which run doesn't have suite and which run do.
|
||||
$suites = array_merge($suites, array(
|
||||
$suitename => array(
|
||||
'paths' => array_values($themesuitefeatures),
|
||||
'contexts' => array_keys($themecontexts[$theme]['suitecontexts']),
|
||||
'contexts' => $themecontexts[$theme],
|
||||
)
|
||||
));
|
||||
}
|
||||
|
@ -1246,7 +1228,7 @@ class behat_config_util {
|
|||
/**
|
||||
* Return theme directory.
|
||||
*
|
||||
* @param string $themename
|
||||
* @param string $themename name of theme
|
||||
* @return string theme directory
|
||||
*/
|
||||
protected function get_theme_test_directory($themename) {
|
||||
|
@ -1339,7 +1321,7 @@ class behat_config_util {
|
|||
|
||||
$tests = array();
|
||||
$testtypes = array(
|
||||
'contexts' => '|behat_.*\.php$|',
|
||||
'contexts' => '|^behat_.*\.php$|',
|
||||
'features' => '|.*\.feature$|',
|
||||
);
|
||||
|
||||
|
@ -1427,91 +1409,72 @@ class behat_config_util {
|
|||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of contexts overridden by themes.
|
||||
*
|
||||
* @return array.
|
||||
*/
|
||||
protected function get_overridden_theme_contexts() {
|
||||
if (empty($this->overriddenthemescontexts)) {
|
||||
$this->overriddenthemescontexts = array();
|
||||
}
|
||||
|
||||
return $this->overriddenthemescontexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of behat contexts for theme and update $this->stepdefinitions list.
|
||||
*
|
||||
* @param string $theme theme name.
|
||||
* @return array list($themecontexts, $themesuitecontexts)
|
||||
* @return List of contexts
|
||||
*/
|
||||
protected function get_behat_contexts_for_theme($theme) {
|
||||
|
||||
protected function get_behat_contexts_for_theme($theme) : array {
|
||||
// If we already have this list then just return. This will not change by run.
|
||||
if (!empty($this->themecontexts[$theme]) && !empty($this->themesuitecontexts)) {
|
||||
return array(
|
||||
'contexts' => $this->themecontexts[$theme],
|
||||
'suitecontexts' => $this->themesuitecontexts[$theme],
|
||||
);
|
||||
if (!empty($this->themecontexts[$theme])) {
|
||||
return $this->themecontexts[$theme];
|
||||
}
|
||||
|
||||
if (empty($this->overriddenthemescontexts)) {
|
||||
$this->overriddenthemescontexts = array();
|
||||
try {
|
||||
$themeconfig = theme_config::load($theme);
|
||||
} catch (Exception $e) {
|
||||
// This theme has no theme config.
|
||||
return [];
|
||||
}
|
||||
|
||||
$contexts = $this->get_components_contexts();
|
||||
// The theme will use all core contexts, except the one overridden by theme or its parent.
|
||||
$parentcontexts = [];
|
||||
if (isset($themeconfig->parents)) {
|
||||
foreach ($themeconfig->parents as $parent) {
|
||||
if ($parentcontexts = $this->get_behat_contexts_for_theme($parent)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create list of contexts used by theme suite.
|
||||
$themecontexts = $this->get_tests_for_theme($theme, 'contexts');
|
||||
if (empty($parentcontexts)) {
|
||||
$parentcontexts = $this->get_components_contexts();
|
||||
}
|
||||
|
||||
// Remove contexts which have been actively blacklisted.
|
||||
$blacklistedcontexts = $this->get_blacklisted_tests_for_theme($theme, 'contexts');
|
||||
|
||||
// Theme suite will use all core contexts, except the one overridden by theme.
|
||||
$themesuitecontexts = $contexts;
|
||||
|
||||
foreach ($themecontexts as $context => $path) {
|
||||
|
||||
// If a context in theme starts with behat_theme_{themename}_behat_* then it's overriding core context.
|
||||
if (preg_match('/^behat_theme_'.$theme.'_(\w+)$/', $context, $match)) {
|
||||
|
||||
if (!empty($themesuitecontexts[$match[1]])) {
|
||||
unset($themesuitecontexts[$match[1]]);
|
||||
}
|
||||
|
||||
// Add this to the list of overridden paths, so it can be added to final contexts list for class resolver.
|
||||
$this->overriddenthemescontexts[$context] = $path;
|
||||
}
|
||||
|
||||
$selectortypes = ['named_partial', 'named_exact'];
|
||||
foreach ($selectortypes as $selectortype) {
|
||||
// Don't include selector classes.
|
||||
if ($context === self::get_behat_theme_selector_override_classname($theme, $selectortype)) {
|
||||
unset($this->contexts[$context]);
|
||||
unset($themesuitecontexts[$context]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add theme specific contexts with suffix to steps definitions.
|
||||
$themesuitecontexts[$context] = $path;
|
||||
}
|
||||
|
||||
// Remove blacklisted contexts.
|
||||
foreach ($blacklistedcontexts as $blacklistpath) {
|
||||
$blacklistcontext = basename($blacklistpath, '.php');
|
||||
|
||||
unset($themesuitecontexts[$blacklistcontext]);
|
||||
unset($parentcontexts[$blacklistcontext]);
|
||||
}
|
||||
|
||||
// We are only interested in the class name of context.
|
||||
$this->themesuitecontexts[$theme] = $themesuitecontexts;
|
||||
$this->themecontexts[$theme] = $themecontexts;
|
||||
// Apply overrides.
|
||||
$contexts = array_merge($parentcontexts, $this->get_tests_for_theme($theme, 'contexts'));
|
||||
|
||||
$retval = array(
|
||||
'contexts' => $themecontexts,
|
||||
'suitecontexts' => $themesuitecontexts,
|
||||
);
|
||||
// Remove classes which are overridden.
|
||||
foreach ($contexts as $contextclass => $path) {
|
||||
require_once($path);
|
||||
if (!class_exists($contextclass)) {
|
||||
// This may be a Poorly named class.
|
||||
continue;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
$rc = new \ReflectionClass($contextclass);
|
||||
$parent = $rc->getParentClass();
|
||||
while ($rc = $rc->getParentClass()) {
|
||||
if (isset($contexts[$rc->name])) {
|
||||
unset($contexts[$rc->name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the list of contexts.
|
||||
ksort($contexts);
|
||||
|
||||
$this->themecontexts[$theme] = $contexts;
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,13 @@ class behat_context_helper {
|
|||
* @return behat_base
|
||||
*/
|
||||
public static function get($classname) {
|
||||
$contexts = self::$environment->getContexts();
|
||||
|
||||
foreach ($contexts as $context) {
|
||||
if (is_a($context, $classname)) {
|
||||
return $context;
|
||||
}
|
||||
}
|
||||
|
||||
$suitename = self::$environment->getSuite()->getName();
|
||||
// If default suite, then get the default theme name.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue