From f49d6249926c3f0fe46b633e4eca5e376c48bc5c Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Mon, 2 Mar 2026 10:37:56 +0000 Subject: [PATCH] MDL-75067 behat: always interact with filepicker inside active dialogue. This allows for tests to interact with multiple elements of this type during scenarios, whereas previously Behat would always try to interact with the first (even when referring to latter file managers). --- .upgradenotes/MDL-75067-2026030210543707.yml | 8 ++++ public/auth/tests/behat/loginform.feature | 6 ++- .../lib/behat/classes/behat_session_trait.php | 12 ++--- public/lib/behat/core_behat_file_helper.php | 44 +++++++------------ 4 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 .upgradenotes/MDL-75067-2026030210543707.yml diff --git a/.upgradenotes/MDL-75067-2026030210543707.yml b/.upgradenotes/MDL-75067-2026030210543707.yml new file mode 100644 index 00000000000..3d8a8b2d04e --- /dev/null +++ b/.upgradenotes/MDL-75067-2026030210543707.yml @@ -0,0 +1,8 @@ +issueNumber: MDL-75067 +notes: + tool_behat: + - message: >- + The `behat_session_trait::ensure_element_[does_not_]exists(...)` methods + now accept optional `$container` parameter to define the parent node to + look within + type: improved diff --git a/public/auth/tests/behat/loginform.feature b/public/auth/tests/behat/loginform.feature index 2f6c37d7e2b..c3563668260 100644 --- a/public/auth/tests/behat/loginform.feature +++ b/public/auth/tests/behat/loginform.feature @@ -34,11 +34,13 @@ Feature: Test if the login form provides the correct feedback Scenario: Set logo for loginpage Given I log in as "admin" And I navigate to "Appearance > Logos" in site administration - And I upload "course/tests/fixtures/image.jpg" file to "Logo" filemanager + And I upload "lib/tests/fixtures/1.jpg" file to "Logo" filemanager + And I upload "lib/tests/fixtures/2.jpg" file to "Favicon" filemanager And I press "Save changes" And I log out And I follow "Log in" - Then "//img[@id='logoimage']" "xpath_element" should exist + Then "//img[@id='logoimage' and contains(@src, '/1.jpg')]" "xpath_element" should exist + And "//link[@rel='shortcut icon' and contains(@href, '/2.jpg')]" "xpath_element" should exist Scenario: Add a custom welcome message Given the following config values are set as admin: diff --git a/public/lib/behat/classes/behat_session_trait.php b/public/lib/behat/classes/behat_session_trait.php index 8394c346a89..3b4e5f62e3f 100644 --- a/public/lib/behat/classes/behat_session_trait.php +++ b/public/lib/behat/classes/behat_session_trait.php @@ -581,9 +581,9 @@ trait behat_session_trait { * @throws ExpectationException * @param string $locator * @param string $selectortype - * @return void + * @param NodeElement $container Restrict the search to just children of the specified container */ - protected function ensure_element_exists($locator, $selectortype) { + protected function ensure_element_exists($locator, $selectortype, $container = false) { // Exception if it timesout and the element is still there. $msg = "The '{$locator}' element does not exist and should"; $exception = new ExpectationException($msg, $this->getSession()); @@ -593,7 +593,7 @@ trait behat_session_trait { 'selector' => $selector, 'locator' => $locator, 'container' => $container, - ] = $this->normalise_selector($selectortype, $locator, $this->getSession()->getPage()); + ] = $this->normalise_selector($selectortype, $locator, $container ?: $this->getSession()->getPage()); // It will stop spinning once the find() method returns true. $this->spin( @@ -616,9 +616,9 @@ trait behat_session_trait { * @throws ExpectationException * @param string $locator * @param string $selectortype - * @return void + * @param NodeElement $container Restrict the search to just children of the specified container */ - protected function ensure_element_does_not_exist($locator, $selectortype) { + protected function ensure_element_does_not_exist($locator, $selectortype, $container = false) { // Exception if it timesout and the element is still there. $msg = "The '{$locator}' element exists and should not exist"; $exception = new ExpectationException($msg, $this->getSession()); @@ -628,7 +628,7 @@ trait behat_session_trait { 'selector' => $selector, 'locator' => $locator, 'container' => $container, - ] = $this->normalise_selector($selectortype, $locator, $this->getSession()->getPage()); + ] = $this->normalise_selector($selectortype, $locator, $container ?: $this->getSession()->getPage()); // It will stop spinning once the find() method returns false. $this->spin( diff --git a/public/lib/behat/core_behat_file_helper.php b/public/lib/behat/core_behat_file_helper.php index 17285ed2c93..afc31dc5519 100644 --- a/public/lib/behat/core_behat_file_helper.php +++ b/public/lib/behat/core_behat_file_helper.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. +require_once(__DIR__ . '/behat_base.php'); + +use Behat\Mink\Exception\ExpectationException; +use Behat\Mink\Element\NodeElement; + /** * Files interactions with behat. * @@ -25,25 +31,6 @@ * @copyright 2013 David Monllaó * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. - -require_once(__DIR__ . '/behat_base.php'); - -use Behat\Mink\Exception\ExpectationException as ExpectationException, - Behat\Mink\Element\NodeElement as NodeElement; - -/** - * Files-related actions. - * - * 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 - */ trait core_behat_file_helper { /** @@ -174,10 +161,8 @@ trait core_behat_file_helper { * @throws ExpectationException Thrown by behat_base::find * @param NodeElement $filemanagernode The filemanager or filepicker form element DOM node. * @param mixed $repositoryname The repo name. - * @return void */ protected function open_add_file_window($filemanagernode, $repositoryname) { - $exception = new ExpectationException('No files can be added to the specified filemanager', $this->getSession()); // We should deal with single-file and multiple-file filemanagers, // catching the exception thrown by behat_base::find() in case is not multiple @@ -186,13 +171,17 @@ trait core_behat_file_helper { $filemanagernode, 'NodeElement' ]); + $filepickerdialogue = $this->find('dialogue', get_string('filepicker', 'core_repository')); + // Wait for the default repository (if any) to load. This checks that // the relevant div exists and that it does not include the loading image. $this->ensure_element_exists( - "//div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" . - "//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content ')]" . - "[not(descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content-loading ')])]", - 'xpath_element'); + "//div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" . + "//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content ')]" . + "[not(descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content-loading ')])]", + 'xpath_element', + $filepickerdialogue, + ); // Getting the repository link and opening it. $repoexception = new ExpectationException('The "' . $repositoryname . '" repository has not been found', $this->getSession()); @@ -200,13 +189,14 @@ trait core_behat_file_helper { // Avoid problems with both double and single quotes in the same string. $repositoryname = behat_context_helper::escape($repositoryname); - // Here we don't need to look inside the selected element because there can only be one modal window. + // Select the repository link from inside the current filepicker dialogue. $repositorylink = $this->find( 'xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-area ')]" . "//descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-name ')]" . "[normalize-space(.)=$repositoryname]", - $repoexception + $repoexception, + $filepickerdialogue, ); // Selecting the repo.