From baa1e5253055bfcb2568288b878049b6c171da9d Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Mon, 1 Aug 2022 10:35:59 +0800 Subject: [PATCH] MDL-75887 behat: Add ability to set value regardless of the editor Prior to this commit, the behat_form_editor integration was hard-coded to use Atto. This change allows other editors to be used to set editor values, and breaks that hard bond. Following this change, any editor is able to define a behat_editor_[name].php file defining a function which meets the following signature: set_editor_value(string $editorid, string $value): void Each editor is responsible for checking whether its own API is available and calling any relevant functions to force the editor to set the content. Please note: Behat is unable to determine the current editor in use on the page automatically. --- lib/behat/classes/behat_context_helper.php | 29 +++++++++++ lib/behat/classes/behat_session_trait.php | 23 +++++++++ lib/behat/classes/settable_editor.php | 37 ++++++++++++++ lib/behat/form_field/behat_form_editor.php | 22 +++------ .../atto/tests/behat/behat_editor_atto.php | 26 +++++++++- .../tests/behat/behat_editor_textarea.php | 48 +++++++++++++++++++ 6 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 lib/behat/classes/settable_editor.php create mode 100644 lib/editor/textarea/tests/behat/behat_editor_textarea.php diff --git a/lib/behat/classes/behat_context_helper.php b/lib/behat/classes/behat_context_helper.php index f8d3eed37bd..2aa65a26232 100644 --- a/lib/behat/classes/behat_context_helper.php +++ b/lib/behat/classes/behat_context_helper.php @@ -26,6 +26,7 @@ // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. use Behat\Testwork\Environment\Environment; +use Behat\Mink\Exception\DriverException; /** * Helper to get behat contexts. @@ -115,6 +116,34 @@ class behat_context_helper { return null; } + /** + * Find all Behat contexts which match the specified context class name prefix. + * + * Moodle uses a consistent class naming scheme for all Behat contexts, whereby the context name is in the format: + * + * behat_{component} + * + * This method will return all contexts which match the specified prefix. + * + * For example, to find all editors, you would pass in 'behat_editor', and this might return: + * - behat_editor_atto + * - behat_editor_textarea + * + * @param string $prefix The prefix to search for + * @return \Behat\Behat\Context\Context[] + */ + public static function get_prefixed_contexts(string $prefix): array { + if (!is_a(self::$environment, \Behat\Behat\Context\Environment\InitializedContextEnvironment::class)) { + throw new DriverException( + 'Cannot get prefixed contexts - the environment is not an InitializedContextEnvironment' + ); + } + + return array_filter(self::$environment->getContexts(), function($context) use ($prefix): bool { + return (strpos(get_class($context), $prefix) === 0); + }); + } + /** * Check for any theme override of the specified class name. * diff --git a/lib/behat/classes/behat_session_trait.php b/lib/behat/classes/behat_session_trait.php index 55b5fc1ad3b..dc9082795ba 100644 --- a/lib/behat/classes/behat_session_trait.php +++ b/lib/behat/classes/behat_session_trait.php @@ -1049,6 +1049,29 @@ EOF; $this->look_for_exceptions(); } + /** + * Execute a function in a specific behat context. + * + * For example, to call the 'set_editor_value' function for all editors, you would call: + * + * behat_base::execute_in_matching_contexts('editor', 'set_editor_value', ['Some value']); + * + * This would find all behat contexts whose class name starts with 'behat_editor_' and + * call the 'set_editor_value' function on that context. + * + * @param string $prefix + * @param string $method + * @param array $params + */ + public static function execute_in_matching_contexts(string $prefix, string $method, array $params): void { + $contexts = behat_context_helper::get_prefixed_contexts("behat_{$prefix}_"); + foreach ($contexts as $context) { + if (method_exists($context, $method) && is_callable([$context, $method])) { + call_user_func_array([$context, $method], $params); + } + } + } + /** * Get the actual user in the behat session (note $USER does not correspond to the behat session's user). * @return mixed diff --git a/lib/behat/classes/settable_editor.php b/lib/behat/classes/settable_editor.php new file mode 100644 index 00000000000..2c5f16f7f79 --- /dev/null +++ b/lib/behat/classes/settable_editor.php @@ -0,0 +1,37 @@ +. + +/** + * Editor interface for setting editor values. + * + * @package behat + * @category test + * @copyright 2022 Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_behat; + +interface settable_editor { + + /** + * Set the editor value. + * + * @param string $editorid The id of the editor within the page + * @param string $value The intended content of the editor + */ + public function set_editor_value(string $editorid, string $value): void; +} diff --git a/lib/behat/form_field/behat_form_editor.php b/lib/behat/form_field/behat_form_editor.php index 96e8c0a92ae..acc00513254 100644 --- a/lib/behat/form_field/behat_form_editor.php +++ b/lib/behat/form_field/behat_form_editor.php @@ -32,7 +32,6 @@ require_once(__DIR__ . '/behat_form_textarea.php'); /** * Moodle editor field. * - * @todo Support for multiple editors * @package core_form * @category test * @copyright 2012 David MonllaĆ³ @@ -44,26 +43,18 @@ class behat_form_editor extends behat_form_textarea { * Sets the value to a field. * * @param string $value - * @return void */ - public function set_value($value) { - + public function set_value($value): void { $editorid = $this->field->getAttribute('id'); if ($this->running_javascript()) { $value = addslashes($value); // This will be transported in JSON, which doesn't allow newlines in strings, so we must escape them. $value = str_replace("\n", "\\n", $value); - $js = ' -(function() { - var editor = Y.one(document.getElementById("'.$editorid.'editable")); - if (editor) { - editor.setHTML("' . $value . '"); - } - editor = Y.one(document.getElementById("'.$editorid.'")); - editor.set("value", "' . $value . '"); -})(); -'; - behat_base::execute_script_in_session($this->session, $js); + behat_base::execute_in_matching_contexts('editor', 'set_editor_value', [ + $editorid, + $value, + ]); + } else { parent::set_value($value); } @@ -106,4 +97,3 @@ class behat_form_editor extends behat_form_textarea { return $this->text_matches($expectedvalue) || $this->text_matches('

' . $expectedvalue . '

'); } } - diff --git a/lib/editor/atto/tests/behat/behat_editor_atto.php b/lib/editor/atto/tests/behat/behat_editor_atto.php index a982bc5cc68..66aae827e91 100644 --- a/lib/editor/atto/tests/behat/behat_editor_atto.php +++ b/lib/editor/atto/tests/behat/behat_editor_atto.php @@ -28,6 +28,7 @@ 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'); +require_once(__DIR__ . '/../../../../behat/classes/settable_editor.php'); /** * Steps definitions to deal with the atto text editor @@ -37,7 +38,30 @@ require_once(__DIR__ . '/../../../../behat/behat_base.php'); * @copyright 2014 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class behat_editor_atto extends behat_base { +class behat_editor_atto extends behat_base implements \core_behat\settable_editor { + + /** + * Set the value for the editor. + * + * @param string $editorid + * @param string $value + */ + public function set_editor_value(string $editorid, string $value): void { + $js = <<execute_script($js); + } /** * Select the text in an Atto field. diff --git a/lib/editor/textarea/tests/behat/behat_editor_textarea.php b/lib/editor/textarea/tests/behat/behat_editor_textarea.php new file mode 100644 index 00000000000..a47908ab7bd --- /dev/null +++ b/lib/editor/textarea/tests/behat/behat_editor_textarea.php @@ -0,0 +1,48 @@ +. + +/** + * Moodle textarea editor field. + * + * @package core_form + * @category test + * @copyright 2022 Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(__DIR__ . '/../../../../behat/behat_base.php'); +require_once(__DIR__ . '/../../../../behat/classes/settable_editor.php'); + +class behat_editor_textarea extends behat_base implements \core_behat\settable_editor { + + /** + * Set the value for the editor. + * + * @param string $editorid + * @param string $value + */ + public function set_editor_value(string $editorid, string $value): void { + $js = <<execute_script($js); + } +}