mirror of
https://github.com/moodle/moodle.git
synced 2025-04-25 10:26:17 +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
admin/tool/behat/tests/fixtures/core
lib/behat
repository
theme/bootstrapbase/tests/behat
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Test context 1
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Test context 2
|
||||
|
@ -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.
|
||||
|
@ -17,9 +17,8 @@
|
||||
/**
|
||||
* Files interactions with behat.
|
||||
*
|
||||
* Note that steps definitions files can not extend other steps definitions files, so
|
||||
* steps definitions which makes use of file attachments or filepicker should
|
||||
* extend behat_files instead of behat_base.
|
||||
* Note that steps definitions files can not extend other steps definitions files, so steps definitions which makes use
|
||||
* of file attachments or filepicker should use this behat_file_helper trait.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
@ -37,16 +36,15 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
/**
|
||||
* Files-related actions.
|
||||
*
|
||||
* Steps definitions related with filepicker or repositories should extend
|
||||
* this class instead of behat_base as it provides useful methods to deal
|
||||
* with the common filepicker issues.
|
||||
* Steps definitions related with filepicker or repositories should extend use this trait as it provides useful methods
|
||||
* to deal with the common filepicker issues.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright 2013 David Monllaó
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_files extends behat_base {
|
||||
trait core_behat_file_helper {
|
||||
|
||||
/**
|
||||
* Gets the NodeElement for filepicker of filemanager moodleform element.
|
||||
@ -276,5 +274,4 @@ class behat_files extends behat_base {
|
||||
$filepickernode
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -25,7 +25,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../lib/behat/behat_files.php');
|
||||
require_once(__DIR__ . '/../../../lib/behat/core_behat_file_helper.php');
|
||||
|
||||
use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
Behat\Gherkin\Node\TableNode as TableNode;
|
||||
@ -33,14 +33,13 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
/**
|
||||
* Steps definitions to deal with the filemanager and filepicker.
|
||||
*
|
||||
* Extends behat_files rather than behat_base as is file-related.
|
||||
*
|
||||
* @package core_filepicker
|
||||
* @category test
|
||||
* @copyright 2013 David Monllaó
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_filepicker extends behat_files {
|
||||
class behat_filepicker extends behat_base {
|
||||
use core_behat_file_helper;
|
||||
|
||||
/**
|
||||
* Creates a folder with specified name in the current folder and in the specified filemanager field.
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../lib/behat/behat_files.php');
|
||||
require_once(__DIR__ . '/../../../../lib/behat/core_behat_file_helper.php');
|
||||
|
||||
use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
Behat\Gherkin\Node\TableNode as TableNode;
|
||||
@ -33,14 +33,14 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
/**
|
||||
* Steps definitions to deal with the upload repository.
|
||||
*
|
||||
* Extends behat_files rather than behat_base as is file-related.
|
||||
*
|
||||
* @package repository_upload
|
||||
* @category test
|
||||
* @copyright 2013 David Monllaó
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_repository_upload extends behat_files {
|
||||
class behat_repository_upload extends behat_base {
|
||||
|
||||
use core_behat_file_helper;
|
||||
|
||||
/**
|
||||
* Uploads a file to the specified filemanager leaving other fields in upload form default. The paths should be relative to moodle codebase.
|
||||
|
@ -34,16 +34,22 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
/**
|
||||
* Steps definitions to deal with the filemanager and filepicker overrides.
|
||||
*
|
||||
* @package theme_bootstrapbase
|
||||
* @category test
|
||||
* @copyright 2016 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_theme_bootstrapbase_behat_filepicker extends behat_theme_bootstrapbase_behat_files {
|
||||
|
||||
class behat_theme_bootstrapbase_behat_filepicker extends behat_filepicker {
|
||||
use theme_bootstrapbase_behat_file_helper;
|
||||
|
||||
public function i_create_folder_in_filemanager($foldername, $filemanagerelement) {
|
||||
|
||||
$fieldnode = $this->get_filepicker_node($filemanagerelement);
|
||||
|
||||
// Looking for the create folder button inside the specified filemanager.
|
||||
$exception = new ExpectationException('No folders can be created in "'.$filemanagerelement.'" filemanager',$this->getSession());
|
||||
$exception = new ExpectationException('No folders can be created in "'.$filemanagerelement.'" filemanager',
|
||||
$this->getSession());
|
||||
$newfolder = $this->find('css', 'div.fp-btn-mkdir a', $exception, $fieldnode);
|
||||
$newfolder->click();
|
||||
|
||||
@ -143,7 +149,8 @@ class behat_theme_bootstrapbase_behat_filepicker extends behat_theme_bootstrapba
|
||||
|
||||
$elements = $this->find_all('xpath', $xpath, false, $filemanagernode);
|
||||
if (count($elements) != $elementscount) {
|
||||
throw new ExpectationException('Found '.count($elements).' elements in filemanager instead of expected '.$elementscount, $this->getSession());
|
||||
throw new ExpectationException('Found '.count($elements).
|
||||
' elements in filemanager instead of expected '.$elementscount, $this->getSession());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../repository/upload/tests/behat/behat_repository_upload.php');
|
||||
require_once(__DIR__ . '/theme_bootstrapbase_behat_file_helper.php');
|
||||
|
||||
use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
Behat\Gherkin\Node\TableNode as TableNode;
|
||||
@ -40,6 +41,8 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
*/
|
||||
class behat_theme_bootstrapbase_behat_repository_upload extends behat_repository_upload {
|
||||
|
||||
use theme_bootstrapbase_behat_file_helper;
|
||||
|
||||
protected function upload_file_to_filemanager($filepath, $filemanagerelement, TableNode $data, $overwriteaction = false) {
|
||||
global $CFG;
|
||||
|
||||
@ -108,5 +111,4 @@ class behat_theme_bootstrapbase_behat_repository_upload extends behat_repository
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../lib/behat/behat_files.php');
|
||||
require_once(__DIR__ . '/../../../../lib/behat/core_behat_file_helper.php');
|
||||
|
||||
use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
Behat\Mink\Element\NodeElement as NodeElement;
|
||||
@ -38,7 +38,11 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
|
||||
* @copyright 2016 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_theme_bootstrapbase_behat_files extends behat_files {
|
||||
trait theme_bootstrapbase_behat_file_helper {
|
||||
|
||||
use core_behat_file_helper {
|
||||
core_behat_file_helper::get_filepicker_node as core_get_filepicker_node;
|
||||
}
|
||||
|
||||
protected function get_filepicker_node($filepickerelement) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user