From 13cc3607de43c9caa62b05c580068da529f395fa Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Mon, 29 Aug 2022 20:46:35 +0800 Subject: [PATCH] MDL-75886 atto: Always use Atto for @atto tests This change, which should be easy to mimic for other editors. This will ensure that the correct editor is used for tests relating to that editor, or its subplugins. --- lib/behat/classes/behat_session_trait.php | 60 +++++++++++++++++++ .../atto/tests/behat/behat_editor_atto.php | 22 ++++++- lib/tests/behat/behat_general.php | 29 +++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/lib/behat/classes/behat_session_trait.php b/lib/behat/classes/behat_session_trait.php index abbc003f897..55b5fc1ad3b 100644 --- a/lib/behat/classes/behat_session_trait.php +++ b/lib/behat/classes/behat_session_trait.php @@ -30,6 +30,7 @@ use Behat\Mink\Exception\ExpectationException; use Behat\Mink\Exception\ElementNotFoundException; use Behat\Mink\Exception\NoSuchWindowException; use Behat\Mink\Session; +use Behat\Testwork\Hook\Scope\HookScope; use Facebook\WebDriver\Exception\ScriptTimeoutException; use Facebook\WebDriver\WebDriverBy; use Facebook\WebDriver\WebDriverElement; @@ -1597,4 +1598,63 @@ EOF; return get_fast_modinfo($course)->get_cm($result->cmid); } + + /** + * Check whether any of the tags availble to the current scope match using the given callable. + * + * This function is typically called from within a Behat Hook, such as BeforeFeature, BeforeScenario, AfterStep, etc. + * + * The callable is used as the second argument to `array_filter()`, and is passed a single string argument for each of the + * tags available in the scope. + * + * The tags passed will include: + * - For a FeatureScope, the Feature tags only + * - For a ScenarioScope, the Feature and Scenario tags + * - For a StepScope, the Feature, Scenario, and Step tags + * + * An example usage may be: + * + * // Note: phpDoc beforeStep attribution not shown. + * public function before_step(StepScope $scope) { + * $callback = function (string $tag): bool { + * return $tag === 'editor_atto' || substr($tag, 0, 5) === 'atto_'; + * }; + * + * if (!self::scope_tags_match($scope, $callback)) { + * return; + * } + * + * // Do something here. + * } + * + * @param HookScope $scope The scope to check + * @param callable $callback The callable to use to check the scope + * @return boolean Whether any of the scope tags match + */ + public static function scope_tags_match(HookScope $scope, callable $callback): bool { + $tags = []; + + if (is_subclass_of($scope, \Behat\Behat\Hook\Scope\FeatureScope::class)) { + $tags = $scope->getFeature()->getTags(); + } + + if (is_subclass_of($scope, \Behat\Behat\Hook\Scope\ScenarioScope::class)) { + $tags = array_merge( + $scope->getFeature()->getTags(), + $scope->getScenario()->getTags() + ); + } + + if (is_subclass_of($scope, \Behat\Behat\Hook\Scope\StepScope::class)) { + $tags = array_merge( + $scope->getFeature()->getTags(), + $scope->getScenario()->getTags(), + $scope->getStep()->getTags() + ); + } + + $matches = array_filter($tags, $callback); + + return !empty($matches); + } } diff --git a/lib/editor/atto/tests/behat/behat_editor_atto.php b/lib/editor/atto/tests/behat/behat_editor_atto.php index 94c9d5a90ab..a982bc5cc68 100644 --- a/lib/editor/atto/tests/behat/behat_editor_atto.php +++ b/lib/editor/atto/tests/behat/behat_editor_atto.php @@ -23,6 +23,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use Behat\Behat\Hook\Scope\BeforeScenarioScope; + // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. require_once(__DIR__ . '/../../../../behat/behat_base.php'); @@ -59,6 +61,24 @@ class behat_editor_atto extends behat_base { $field->select_text(); } + /** + * Ensure that the Atto editor is used for all tests using the editor_atto, or atto_* tags. + * + * This ensures, whatever the default editor, that the Atto editor is used for these tests. + * + * @BeforeScenario + * @param BeforeScenarioScope $scope The Behat Scope + */ + public function set_default_editor_flag(BeforeScenarioScope $scope): void { + // This only applies to a scenario which matches the editor_atto, or an atto subplugin. + $callback = function (string $tag): bool { + return $tag === 'editor_atto' || substr($tag, 0, 5) === 'atto_'; + }; + if (!self::scope_tags_match($scope, $callback)) { + return; + } + + $this->execute('behat_general::the_default_editor_is_set_to', ['atto']); + } } - diff --git a/lib/tests/behat/behat_general.php b/lib/tests/behat/behat_general.php index 72a893fb46c..18103b8d9ac 100644 --- a/lib/tests/behat/behat_general.php +++ b/lib/tests/behat/behat_general.php @@ -2190,4 +2190,33 @@ EOF; $class = core_plugin_manager::resolve_plugininfo_class($plugintype); $class::enable_plugin($plugin, true); } + + /** + * Set the default text editor to the named text editor. + * + * @Given the default editor is set to :editor + * @param string $editor + * @throws ExpectationException If the specified editor is not available. + */ + public function the_default_editor_is_set_to(string $editor): void { + global $CFG; + + // Check if the provided editor is available. + if (!array_key_exists($editor, editors_get_available())) { + throw new ExpectationException( + "Unable to set the editor to {$editor} as it is not installed. The available editors are: " . + implode(', ', array_keys(editors_get_available())), + $this->getSession() + ); + } + + // Make the provided editor the default one in $CFG->texteditors by + // moving it to the first [editor],atto,tiny,tinymce,textarea on the list. + $list = explode(',', $CFG->texteditors); + array_unshift($list, $editor); + $list = array_unique($list); + + // Set the list new list of editors. + set_config('texteditors', implode(',', $list)); + } }