diff --git a/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php b/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php index f5231162059..b80713c60c6 100644 --- a/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php +++ b/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php @@ -114,12 +114,8 @@ class behat_block_site_main_menu extends behat_base { protected function get_site_menu_activity_element($element, $selectortype, $activityname) { $activitynode = $this->get_site_menu_activity_node($activityname); - // Transforming to Behat selector/locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . - $selectortype . '" in "' . $activityname . '" '); - - return $this->find($selector, $locator, $exception, $activitynode); + $exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'"); + return $this->find($selectortype, $element, $exception, $activitynode); } /** diff --git a/blocks/social_activities/tests/behat/behat_block_social_activities.php b/blocks/social_activities/tests/behat/behat_block_social_activities.php index 2fe5526d473..8c4f836b896 100644 --- a/blocks/social_activities/tests/behat/behat_block_social_activities.php +++ b/blocks/social_activities/tests/behat/behat_block_social_activities.php @@ -114,12 +114,8 @@ class behat_block_social_activities extends behat_base { protected function get_social_block_activity_element($element, $selectortype, $activityname) { $activitynode = $this->get_social_block_activity_node($activityname); - // Transforming to Behat selector/locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . - $selectortype . '" in "' . $activityname . '" '); - - return $this->find($selector, $locator, $exception, $activitynode); + $exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'"); + return $this->find($selectortype, $element, $exception, $activitynode); } /** diff --git a/course/tests/behat/behat_course.php b/course/tests/behat/behat_course.php index 35465843b41..16fa6e3e3ad 100644 --- a/course/tests/behat/behat_course.php +++ b/course/tests/behat/behat_course.php @@ -1144,11 +1144,8 @@ class behat_course extends behat_base { protected function get_activity_element($element, $selectortype, $activityname) { $activitynode = $this->get_activity_node($activityname); - // Transforming to Behat selector/locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . $selectortype . '" in "' . $activityname . '" '); - - return $this->find($selector, $locator, $exception, $activitynode); + $exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'"); + return $this->find($selectortype, $element, $exception, $activitynode); } /** diff --git a/lib/behat/behat_base.php b/lib/behat/behat_base.php index c42d38ef5d7..c6053b9106b 100644 --- a/lib/behat/behat_base.php +++ b/lib/behat/behat_base.php @@ -381,12 +381,7 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext { * @return NodeElement */ protected function get_selected_node($selectortype, $element) { - - // Getting Mink selector and locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - - // Returns the NodeElement. - return $this->find($selector, $locator); + return $this->find($selectortype, $element); } /** @@ -398,7 +393,6 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext { * @return NodeElement */ protected function get_text_selector_node($selectortype, $element) { - // Getting Mink selector and locator. list($selector, $locator) = $this->transform_text_selector($selectortype, $element); @@ -417,18 +411,13 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext { * @return NodeElement */ protected function get_node_in_container($selectortype, $element, $containerselectortype, $containerelement) { - // Gets the container, it will always be text based. $containernode = $this->get_text_selector_node($containerselectortype, $containerelement); - list($selector, $locator) = $this->transform_selector($selectortype, $element); - - // Specific exception giving info about where can't we find the element. $locatorexceptionmsg = $element . '" in the "' . $containerelement. '" "' . $containerselectortype. '"'; $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $locatorexceptionmsg); - // Looks for the requested node inside the container node. - return $this->find($selector, $locator, $exception, $containernode); + return $this->find($selectortype, $element, $exception, $containernode); } /** @@ -447,7 +436,6 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext { * @return array Contains the selector and the locator expected by Mink. */ protected function transform_selector($selectortype, $element) { - // Here we don't know if an allowed text selector is being used. $selectors = behat_selectors::get_allowed_selectors(); if (!isset($selectors[$selectortype])) { @@ -511,63 +499,68 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext { * Spins around an element until it exists * * @throws ExpectationException - * @param string $element + * @param string $locator * @param string $selectortype * @return void */ - protected function ensure_element_exists($element, $selectortype) { - - // Getting the behat selector & locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - + protected function ensure_element_exists($locator, $selectortype) { // Exception if it timesout and the element is still there. - $msg = 'The "' . $element . '" element does not exist and should exist'; + $msg = "The '{$locator}' element does not exist and should"; $exception = new ExpectationException($msg, $this->getSession()); + // Normalise the values in order to perform the search. + [ + 'selector' => $selector, + 'locator' => $locator, + 'container' => $container, + ] = $this->normalise_selector($selectortype, $locator, $this->getSession()->getPage()); + // It will stop spinning once the find() method returns true. $this->spin( - function($context, $args) { - // We don't use behat_base::find as it is already spinning. - if ($context->getSession()->getPage()->find($args['selector'], $args['locator'])) { + function() use ($selector, $locator, $container) { + if ($container->find($selector, $locator)) { return true; } return false; }, - array('selector' => $selector, 'locator' => $locator), + [], self::get_extended_timeout(), $exception, true ); - } /** * Spins until the element does not exist * * @throws ExpectationException - * @param string $element + * @param string $locator * @param string $selectortype * @return void */ - protected function ensure_element_does_not_exist($element, $selectortype) { - - // Getting the behat selector & locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - + protected function ensure_element_does_not_exist($locator, $selectortype) { // Exception if it timesout and the element is still there. - $msg = 'The "' . $element . '" element exists and should not exist'; + $msg = "The '{$locator}' element exists and should not exist"; $exception = new ExpectationException($msg, $this->getSession()); + // Normalise the values in order to perform the search. + [ + 'selector' => $selector, + 'locator' => $locator, + 'container' => $container, + ] = $this->normalise_selector($selectortype, $locator, $this->getSession()->getPage()); + // It will stop spinning once the find() method returns false. $this->spin( - function($context, $args) { - // We don't use behat_base::find() as we are already spinning. - if (!$context->getSession()->getPage()->find($args['selector'], $args['locator'])) { - return true; + function() use ($selector, $locator, $container) { + if ($container->find($selector, $locator)) { + return false; } - return false; + return true; }, - array('selector' => $selector, 'locator' => $locator), + // Note: We cannot use $this because the find will then be $this->find(), which leads us to a nested spin(). + // We cannot nest spins because the outer spin times out before the inner spin completes. + [], self::get_extended_timeout(), $exception, true diff --git a/lib/tests/behat/behat_general.php b/lib/tests/behat/behat_general.php index 07902bb1ecc..bf6659ed092 100644 --- a/lib/tests/behat/behat_general.php +++ b/lib/tests/behat/behat_general.php @@ -412,24 +412,22 @@ class behat_general extends behat_base { * @param string $containerelement * @param string $containerselectortype */ - public function i_drag_and_i_drop_it_in($element, $selectortype, $containerelement, $containerselectortype) { - - list($sourceselector, $sourcelocator) = $this->transform_selector($selectortype, $element); - $sourcexpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($sourceselector, $sourcelocator); - - list($containerselector, $containerlocator) = $this->transform_selector($containerselectortype, $containerelement); - $destinationxpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($containerselector, $containerlocator); - - $node = $this->get_selected_node("xpath_element", $sourcexpath); - if (!$node->isVisible()) { - throw new ExpectationException('"' . $sourcexpath . '" "xpath_element" is not visible', $this->getSession()); - } - $node = $this->get_selected_node("xpath_element", $destinationxpath); - if (!$node->isVisible()) { - throw new ExpectationException('"' . $destinationxpath . '" "xpath_element" is not visible', $this->getSession()); + public function i_drag_and_i_drop_it_in($source, $sourcetype, $target, $targettype) { + if (!$this->running_javascript()) { + throw new DriverException('Drag and drop steps require javascript'); } - $this->getSession()->getDriver()->dragTo($sourcexpath, $destinationxpath); + $source = $this->find($sourcetype, $source); + $target = $this->find($targettype, $target); + + if (!$source->isVisible()) { + throw new ExpectationException("'{$source}' '{$sourcetype}' is not visible", $this->getSession()); + } + if (!$target->isVisible()) { + throw new ExpectationException("'{$target}' '{$targettype}' is not visible", $this->getSession()); + } + + $this->getSession()->getDriver()->dragTo($source->getXpath(), $target->getXpath()); } /** @@ -968,12 +966,8 @@ EOF; * @param string $selectortype The selector type */ public function should_exist($element, $selectortype) { - - // Getting Mink selector and locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - // Will throw an ElementNotFoundException if it does not exist. - $this->find($selector, $locator); + $this->find($selectortype, $element); } /** @@ -987,35 +981,27 @@ EOF; * @param string $selectortype The selector type */ public function should_not_exist($element, $selectortype) { - - // Getting Mink selector and locator. - list($selector, $locator) = $this->transform_selector($selectortype, $element); - + // Will throw an ElementNotFoundException if it does not exist, but, actually it should not exist, so we try & + // catch it. try { - - // Using directly the spin method as we want a reduced timeout but there is no - // need for a 0.1 seconds interval because in the optimistic case we will timeout. - $params = array('selector' => $selector, 'locator' => $locator); // The exception does not really matter as we will catch it and will never "explode". $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $element); + // Using the spin method as we want a reduced timeout but there is no need for a 0.1 seconds interval + // because in the optimistic case we will timeout. // If all goes good it will throw an ElementNotFoundExceptionn that we will catch. $this->spin( - function($context, $args) { - return $context->getSession()->getPage()->findAll($args['selector'], $args['locator']); - }, - $params, - behat_base::get_reduced_timeout(), - $exception, - false + function($context, $args) use ($selectortype, $element) { + return $this->find($selectortype, $element); + }, [], behat_base::get_reduced_timeout(), $exception, false ); } catch (ElementNotFoundException $e) { - // It passes. + // We expect the element to not be found. return; } - throw new ExpectationException('The "' . $element . '" "' . $selectortype . - '" exists in the current page', $this->getSession()); + // The element was found and should not have been. Throw an exception. + throw new ExpectationException("The '{$element}' '{$selectortype}' exists in the current page", $this->getSession()); } /** @@ -1159,16 +1145,14 @@ EOF; */ public function should_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) { // Get the container node. - $containernode = $this->get_selected_node($containerselectortype, $containerelement); - - list($selector, $locator) = $this->transform_selector($selectortype, $element); + $containernode = $this->find($containerselectortype, $containerelement); // Specific exception giving info about where can't we find the element. - $locatorexceptionmsg = $element . '" in the "' . $containerelement. '" "' . $containerselectortype. '"'; + $locatorexceptionmsg = "{$element} in the {$containerelement} {$containerselectortype}"; $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $locatorexceptionmsg); // Looks for the requested node inside the container node. - $this->find($selector, $locator, $exception, $containernode); + $this->find($selectortype, $element, $exception, $containernode); } /** @@ -1184,26 +1168,24 @@ EOF; * @param string $containerselectortype The container locator */ public function should_not_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) { + // Get the container node. + $containernode = $this->find($containerselectortype, $containerelement); - // Get the container node; here we throw an exception - // if the container node does not exist. - $containernode = $this->get_selected_node($containerselectortype, $containerelement); - - list($selector, $locator) = $this->transform_selector($selectortype, $element); - - // Will throw an ElementNotFoundException if it does not exist, but, actually - // it should not exist, so we try & catch it. + // Will throw an ElementNotFoundException if it does not exist, but, actually it should not exist, so we try & + // catch it. try { - // Would be better to use a 1 second sleep because the element should not be there, - // but we would need to duplicate the whole find_all() logic to do it, the benefit of - // changing to 1 second sleep is not significant. - $this->find($selector, $locator, false, $containernode, behat_base::get_reduced_timeout()); + // Looks for the requested node inside the container node. + $this->find($selectortype, $element, false, $containernode, behat_base::get_reduced_timeout()); } catch (ElementNotFoundException $e) { - // It passes. + // We expect the element to not be found. return; } - throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the "' . - $containerelement . '" "' . $containerselectortype . '"', $this->getSession()); + + // The element was found and should not have been. Throw an exception. + throw new ExpectationException( + "The '{$element}' '{$selectortype}' exists in the '{$containerelement}' '{$containerselectortype}'", + $this->getSession() + ); } /** @@ -1794,8 +1776,8 @@ EOF; if (!$this->running_javascript()) { throw new DriverException('Checking focus on an element requires JavaScript'); } - list($a, $b) = $this->transform_selector($nodeselectortype, $nodeelement); - $element = $this->find($a, $b); + + $element = $this->find($nodeselectortype, $nodeelement); $xpath = addslashes_js($element->getXpath()); $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';