Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Navigation step definition overrides for the Classic theme.
  19   *
  20   * @package    theme_classic
  21   * @category   test
  22   * @copyright  2019 Michael Hawkins
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  // NOTE: No MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
  27  
  28  require_once (__DIR__ . '/../../../../lib/tests/behat/behat_navigation.php');
  29  
  30  use Behat\Mink\Exception\ExpectationException as ExpectationException;
  31  use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
  32  
  33  /**
  34   * Step definitions and overrides to navigate through the navigation tree nodes in the Classic theme.
  35   *
  36   * @package    theme_classic
  37   * @category   test
  38   * @copyright  2019 Michael Hawkins
  39   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class behat_theme_classic_behat_navigation extends behat_navigation {
  42      /**
  43       * Navigate to an item in a current page administration menu.
  44       *
  45       * @throws ExpectationException
  46       * @param string $nodetext The navigation node/path to follow, eg "Course administration > Edit settings"
  47       * @return void
  48       */
  49      public function i_navigate_to_in_current_page_administration($nodetext) {
  50          $parentnodes = array_map('trim', explode('>', $nodetext));
  51  
  52          // Find the name of the first category of the administration block tree.
  53          $xpath = "//section[contains(@class,'block_settings')]//div[@id='settingsnav']/ul[1]/li[1]/p[1]/span";
  54          $node = $this->find('xpath', $xpath);
  55  
  56          array_unshift($parentnodes, $node->getText());
  57          $lastnode = array_pop($parentnodes);
  58          $this->select_node_in_navigation($lastnode, $parentnodes);
  59      }
  60  
  61      /**
  62       * Navigate to an item within the site administration menu.
  63       *
  64       * @throws ExpectationException
  65       * @param string $nodetext The navigation node/path to follow, excluding "Site administration" itself, eg "Grades > Scales"
  66       * @return void
  67       */
  68      public function i_navigate_to_in_site_administration($nodetext) {
  69          $parentnodes = array_map('trim', explode('>', $nodetext));
  70          array_unshift($parentnodes, get_string('administrationsite'));
  71          $lastnode = array_pop($parentnodes);
  72          $this->select_node_in_navigation($lastnode, $parentnodes);
  73      }
  74  
  75      /**
  76       * Helper function to get top navigation node in the tree.
  77       *
  78       * @throws ExpectationException if node not found.
  79       * @param string $nodetext name of top navigation node in tree.
  80       * @return NodeElement
  81       */
  82      protected function get_top_navigation_node($nodetext) {
  83          // Avoid problems with quotes.
  84          $nodetextliteral = behat_context_helper::escape($nodetext);
  85          $exception = new ExpectationException('Top navigation node "' . $nodetext . '" not found', $this->getSession());
  86  
  87          $xpath = // Navigation block.
  88                  "//div[contains(concat(' ', normalize-space(@class), ' '), ' content ')]" .
  89                  "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
  90                  "/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" .
  91                  "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" .
  92                  "[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
  93                  "[span[normalize-space(.)={$nodetextliteral}] or a[normalize-space(.)={$nodetextliteral}]]]" .
  94                  "|" .
  95                  // Administration block.
  96                  "//div[contains(concat(' ', normalize-space(@class), ' '), ' content ')]/div" .
  97                  "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
  98                  "/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" .
  99                  "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" .
 100                  "[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
 101                  "/span[normalize-space(.)={$nodetextliteral}]]" .
 102                  "|" .
 103                  "//div[contains(concat(' ', normalize-space(@class), ' '), ' content ')]/div" .
 104                  "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
 105                  "/li[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
 106                  "/span[normalize-space(.)={$nodetextliteral}]]" .
 107                  "|" .
 108                  "//div[contains(concat(' ', normalize-space(@class), ' '), ' content ')]/div" .
 109                  "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
 110                  "/li[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
 111                  "/a[normalize-space(.)={$nodetextliteral}]]";
 112  
 113          $node = $this->find('xpath', $xpath, $exception);
 114  
 115          return $node;
 116      }
 117  
 118      /**
 119       * Check that current page administration contains an element.
 120       *
 121       * @throws ElementNotFoundException
 122       * @param string $element The locator of the specified selector.
 123       *     This may be a path, for example "Subscription mode > Forced subscription"
 124       * @param string $selectortype The selector type (link or text)
 125       * @return void
 126       */
 127      public function should_exist_in_current_page_administration($element, $selectortype) {
 128          $nodes = array_map('trim', explode('>', $element));
 129          $nodetext = end($nodes);
 130  
 131          // Find administration menu.
 132          $rootxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(true);
 133          $menuxpath = $rootxpath . '/p/../ul[1]';
 134  
 135          for ($i = 0; $i < (count($nodes) - 1); $i++) {
 136              $menuxpath .= "/li/p/span[contains(text(), '{$nodes[$i]}')]/../../ul[1]";
 137          }
 138  
 139          if ($selectortype == 'link') {
 140              $menuxpath .= "/li/p[a[contains(text(), '{$nodetext}')]";
 141              $menuxpath .= "|a/span[contains(text(), '{$nodetext}')]]";
 142          } else {
 143              $menuxpath .= "/li/p/span[contains(text(), '{$nodes[$i]}')]";
 144          }
 145  
 146          $exception = new ElementNotFoundException($this->getSession(), "\"{$element}\" \"{$selectortype}\"");
 147          $this->find('xpath', $menuxpath, $exception);
 148      }
 149  
 150      /**
 151       * Check that current page administration does not contains an element.
 152       *
 153       * @throws ExpectationException
 154       * @param string $element The locator of the specified selector.
 155       *     This may be a path, for example "Subscription mode > Forced subscription"
 156       * @param string $selectortype The selector type (link or text)
 157       * @return void
 158       */
 159      public function should_not_exist_in_current_page_administration($element, $selectortype) {
 160          try {
 161              $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(true);
 162          } catch (Exception $e) {
 163              // If an exception was thrown, it means the root note does not exist, so we can conclude the test is a success.
 164              return;
 165          }
 166  
 167          // Test if the element exists.
 168          try {
 169              $this->should_exist_in_current_page_administration($element, $selectortype);
 170          } catch (ElementNotFoundException $e) {
 171  
 172              // If an exception was thrown, it means the element does not exist, so the test is successful.
 173              return;
 174          }
 175  
 176          // If the try block passed, the element exists, so throw an exception.
 177          $exception = 'The "' . $element . '" "' . $selectortype . '" was found, but should not exist';
 178          throw new ExpectationException($exception, $this->getSession());
 179      }
 180  
 181      /**
 182       * Check that the page administration menu exists on the page.
 183       *
 184       * This confirms the existence of the menu, which authorised users should have access to.
 185       * @Given /^I should see the page administration menu$/
 186       *
 187       * @throws ExpectationException
 188       * @return void
 189       */
 190      public function page_administration_exists() {
 191          $menuxpath = "//section[contains(@class,'block_settings')]//div[@id='settingsnav']";
 192          $this->ensure_element_exists($menuxpath, 'xpath_element');
 193      }
 194  
 195      /**
 196       * Check that the page administration menu does not exist on the page.
 197       *
 198       * This confirms the absence of the menu, which unauthorised users should not have access to.
 199       * @Given /^I should not see the page administration menu$/
 200       *
 201       * @throws ExpectationException
 202       * @return void
 203       */
 204      public function page_administration_does_not_exist() {
 205          $menuxpath = "//section[contains(@class,'block_settings')]//div[@id='settingsnav']";
 206          $this->ensure_element_does_not_exist($menuxpath, 'xpath_element');
 207      }
 208  
 209      /**
 210       * Locate the administration menu on the page (but not in the header) and return its xpath.
 211       *
 212       * @throws ElementNotFoundException
 213       * @param bool $mustexist If true, throws an exception if menu is not found
 214       * @return null|string
 215       */
 216      protected function find_page_administration_menu($mustexist = false) {
 217          $menuxpath = "//section[contains(@class,'block_settings')]//div[@id='settingsnav']/ul[1]/li[1]";
 218  
 219          if ($mustexist) {
 220              $exception = new ElementNotFoundException($this->getSession(), 'Page administration menu');
 221              $this->find('xpath', $menuxpath, $exception);
 222  
 223          } else if (!$this->getSession()->getPage()->find('xpath', $menuxpath)) {
 224              return null;
 225          }
 226  
 227          return $menuxpath;
 228      }
 229  }