| 1 | 
           efrain | 
           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 | 
            * General use steps definitions.
  | 
        
        
            | 
            | 
           19 | 
            *
  | 
        
        
            | 
            | 
           20 | 
            * @package   core
  | 
        
        
            | 
            | 
           21 | 
            * @category  test
  | 
        
        
            | 
            | 
           22 | 
            * @copyright 2012 David Monllaó
  | 
        
        
            | 
            | 
           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__ . '/../../behat/behat_base.php');
  | 
        
        
            | 
            | 
           29 | 
              | 
        
        
            | 
            | 
           30 | 
           use Behat\Gherkin\Node\TableNode;
  | 
        
        
            | 
            | 
           31 | 
           use Behat\Mink\Element\NodeElement;
  | 
        
        
            | 
            | 
           32 | 
           use Behat\Mink\Exception\DriverException;
  | 
        
        
            | 
            | 
           33 | 
           use Behat\Mink\Exception\ElementNotFoundException;
  | 
        
        
            | 
            | 
           34 | 
           use Behat\Mink\Exception\ExpectationException;
  | 
        
        
           | 11 | 
           efrain | 
           35 | 
           use Facebook\WebDriver\Exception\NoSuchAlertException;
  | 
        
        
           | 1 | 
           efrain | 
           36 | 
           use Facebook\WebDriver\Exception\NoSuchElementException;
  | 
        
        
            | 
            | 
           37 | 
           use Facebook\WebDriver\Exception\StaleElementReferenceException;
  | 
        
        
           | 11 | 
           efrain | 
           38 | 
           use Facebook\WebDriver\WebDriverAlert;
  | 
        
        
            | 
            | 
           39 | 
           use Facebook\WebDriver\WebDriverExpectedCondition;
  | 
        
        
           | 1 | 
           efrain | 
           40 | 
              | 
        
        
            | 
            | 
           41 | 
           /**
  | 
        
        
            | 
            | 
           42 | 
            * Cross component steps definitions.
  | 
        
        
            | 
            | 
           43 | 
            *
  | 
        
        
            | 
            | 
           44 | 
            * Basic web application definitions from MinkExtension and
  | 
        
        
            | 
            | 
           45 | 
            * BehatchExtension. Definitions modified according to our needs
  | 
        
        
            | 
            | 
           46 | 
            * when necessary and including only the ones we need to avoid
  | 
        
        
            | 
            | 
           47 | 
            * overlapping and confusion.
  | 
        
        
            | 
            | 
           48 | 
            *
  | 
        
        
            | 
            | 
           49 | 
            * @package   core
  | 
        
        
            | 
            | 
           50 | 
            * @category  test
  | 
        
        
            | 
            | 
           51 | 
            * @copyright 2012 David Monllaó
  | 
        
        
            | 
            | 
           52 | 
            * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  | 
        
        
            | 
            | 
           53 | 
            */
  | 
        
        
            | 
            | 
           54 | 
           class behat_general extends behat_base {
  | 
        
        
            | 
            | 
           55 | 
              | 
        
        
            | 
            | 
           56 | 
               /**
  | 
        
        
            | 
            | 
           57 | 
                * @var string used by {@link switch_to_window()} and
  | 
        
        
            | 
            | 
           58 | 
                * {@link switch_to_the_main_window()} to work-around a Chrome browser issue.
  | 
        
        
            | 
            | 
           59 | 
                */
  | 
        
        
            | 
            | 
           60 | 
               const MAIN_WINDOW_NAME = '__moodle_behat_main_window_name';
  | 
        
        
            | 
            | 
           61 | 
              | 
        
        
            | 
            | 
           62 | 
               /**
  | 
        
        
            | 
            | 
           63 | 
                * @var string when we want to check whether or not a new page has loaded,
  | 
        
        
            | 
            | 
           64 | 
                * we first write this unique string into the page. Then later, by checking
  | 
        
        
            | 
            | 
           65 | 
                * whether it is still there, we can tell if a new page has been loaded.
  | 
        
        
            | 
            | 
           66 | 
                */
  | 
        
        
            | 
            | 
           67 | 
               const PAGE_LOAD_DETECTION_STRING = 'new_page_not_loaded_since_behat_started_watching';
  | 
        
        
            | 
            | 
           68 | 
              | 
        
        
            | 
            | 
           69 | 
               /**
  | 
        
        
            | 
            | 
           70 | 
                * @var $pageloaddetectionrunning boolean Used to ensure that page load detection was started before a page reload
  | 
        
        
            | 
            | 
           71 | 
                * was checked for.
  | 
        
        
            | 
            | 
           72 | 
                */
  | 
        
        
            | 
            | 
           73 | 
               private $pageloaddetectionrunning = false;
  | 
        
        
            | 
            | 
           74 | 
              | 
        
        
            | 
            | 
           75 | 
               /**
  | 
        
        
            | 
            | 
           76 | 
                * Opens Moodle homepage.
  | 
        
        
            | 
            | 
           77 | 
                *
  | 
        
        
            | 
            | 
           78 | 
                * @Given /^I am on homepage$/
  | 
        
        
            | 
            | 
           79 | 
                */
  | 
        
        
            | 
            | 
           80 | 
               public function i_am_on_homepage() {
  | 
        
        
           | 1441 | 
           ariadna | 
           81 | 
                   $this->execute([self::class, 'i_visit'], ['/']);
  | 
        
        
           | 1 | 
           efrain | 
           82 | 
               }
  | 
        
        
            | 
            | 
           83 | 
              | 
        
        
            | 
            | 
           84 | 
               /**
  | 
        
        
            | 
            | 
           85 | 
                * Opens Moodle site homepage.
  | 
        
        
            | 
            | 
           86 | 
                *
  | 
        
        
            | 
            | 
           87 | 
                * @Given /^I am on site homepage$/
  | 
        
        
            | 
            | 
           88 | 
                */
  | 
        
        
            | 
            | 
           89 | 
               public function i_am_on_site_homepage() {
  | 
        
        
           | 1441 | 
           ariadna | 
           90 | 
                   $this->execute([self::class, 'i_visit'], ['/?redirect=0']);
  | 
        
        
           | 1 | 
           efrain | 
           91 | 
               }
  | 
        
        
            | 
            | 
           92 | 
              | 
        
        
            | 
            | 
           93 | 
               /**
  | 
        
        
            | 
            | 
           94 | 
                * Opens course index page.
  | 
        
        
            | 
            | 
           95 | 
                *
  | 
        
        
            | 
            | 
           96 | 
                * @Given /^I am on course index$/
  | 
        
        
            | 
            | 
           97 | 
                */
  | 
        
        
            | 
            | 
           98 | 
               public function i_am_on_course_index() {
  | 
        
        
           | 1441 | 
           ariadna | 
           99 | 
                   $this->execute([self::class, 'i_visit'], ['/course/index.php']);
  | 
        
        
           | 1 | 
           efrain | 
           100 | 
               }
  | 
        
        
            | 
            | 
           101 | 
              | 
        
        
            | 
            | 
           102 | 
               /**
  | 
        
        
           | 1441 | 
           ariadna | 
           103 | 
                * Checks, that current page PATH matches regular expression
  | 
        
        
            | 
            | 
           104 | 
                *
  | 
        
        
            | 
            | 
           105 | 
                * Example: Then the url should match "/course/index\.php"
  | 
        
        
            | 
            | 
           106 | 
                * Example: Then the url should match "/mod/forum/view\.php\?id=[0-9]+"
  | 
        
        
            | 
            | 
           107 | 
                * Example: And the url should match "^http://moodle\.org"
  | 
        
        
            | 
            | 
           108 | 
                *
  | 
        
        
            | 
            | 
           109 | 
                * @Then /^the url should match (?P<pattern>"(?:[^"]|\\")*")$/
  | 
        
        
            | 
            | 
           110 | 
                * @param string $pattern The pattern that must match to the current url.
  | 
        
        
            | 
            | 
           111 | 
                */
  | 
        
        
            | 
            | 
           112 | 
               public function the_url_should_match($pattern) {
  | 
        
        
            | 
            | 
           113 | 
                   $url = $this->getSession()->getCurrentUrl();
  | 
        
        
            | 
            | 
           114 | 
              | 
        
        
            | 
            | 
           115 | 
                   if (preg_match($pattern, $url) === 1) {
  | 
        
        
            | 
            | 
           116 | 
                       return;
  | 
        
        
            | 
            | 
           117 | 
                   }
  | 
        
        
            | 
            | 
           118 | 
              | 
        
        
            | 
            | 
           119 | 
                   throw new ExpectationException(sprintf('The url "%s" should match with %s', $url, $pattern), $this->getSession());
  | 
        
        
            | 
            | 
           120 | 
               }
  | 
        
        
            | 
            | 
           121 | 
              | 
        
        
            | 
            | 
           122 | 
               /**
  | 
        
        
           | 1 | 
           efrain | 
           123 | 
                * Reloads the current page.
  | 
        
        
            | 
            | 
           124 | 
                *
  | 
        
        
            | 
            | 
           125 | 
                * @Given /^I reload the page$/
  | 
        
        
            | 
            | 
           126 | 
                */
  | 
        
        
            | 
            | 
           127 | 
               public function reload() {
  | 
        
        
            | 
            | 
           128 | 
                   $this->getSession()->reload();
  | 
        
        
            | 
            | 
           129 | 
               }
  | 
        
        
            | 
            | 
           130 | 
              | 
        
        
            | 
            | 
           131 | 
               /**
  | 
        
        
            | 
            | 
           132 | 
                * Follows the page redirection. Use this step after any action that shows a message and waits for a redirection
  | 
        
        
            | 
            | 
           133 | 
                *
  | 
        
        
            | 
            | 
           134 | 
                * @Given /^I wait to be redirected$/
  | 
        
        
            | 
            | 
           135 | 
                */
  | 
        
        
            | 
            | 
           136 | 
               public function i_wait_to_be_redirected() {
  | 
        
        
            | 
            | 
           137 | 
              | 
        
        
            | 
            | 
           138 | 
                   // Xpath and processes based on core_renderer::redirect_message(), core_renderer::$metarefreshtag and
  | 
        
        
            | 
            | 
           139 | 
                   // moodle_page::$periodicrefreshdelay possible values.
  | 
        
        
            | 
            | 
           140 | 
                   if (!$metarefresh = $this->getSession()->getPage()->find('xpath', "//head/descendant::meta[@http-equiv='refresh']")) {
  | 
        
        
            | 
            | 
           141 | 
                       // We don't fail the scenario if no redirection with message is found to avoid race condition false failures.
  | 
        
        
            | 
            | 
           142 | 
                       return true;
  | 
        
        
            | 
            | 
           143 | 
                   }
  | 
        
        
            | 
            | 
           144 | 
              | 
        
        
            | 
            | 
           145 | 
                   // Wrapped in try & catch in case the redirection has already been executed.
  | 
        
        
            | 
            | 
           146 | 
                   try {
  | 
        
        
            | 
            | 
           147 | 
                       $content = $metarefresh->getAttribute('content');
  | 
        
        
            | 
            | 
           148 | 
                   } catch (NoSuchElementException $e) {
  | 
        
        
            | 
            | 
           149 | 
                       return true;
  | 
        
        
            | 
            | 
           150 | 
                   } catch (StaleElementReferenceException $e) {
  | 
        
        
            | 
            | 
           151 | 
                       return true;
  | 
        
        
            | 
            | 
           152 | 
                   }
  | 
        
        
            | 
            | 
           153 | 
              | 
        
        
            | 
            | 
           154 | 
                   // Getting the refresh time and the url if present.
  | 
        
        
            | 
            | 
           155 | 
                   if (strstr($content, 'url') != false) {
  | 
        
        
            | 
            | 
           156 | 
              | 
        
        
           | 1441 | 
           ariadna | 
           157 | 
                       [$waittime, $url] = explode(';', $content);
  | 
        
        
           | 1 | 
           efrain | 
           158 | 
              | 
        
        
            | 
            | 
           159 | 
                       // Cleaning the URL value.
  | 
        
        
            | 
            | 
           160 | 
                       $url = trim(substr($url, strpos($url, 'http')));
  | 
        
        
            | 
            | 
           161 | 
              | 
        
        
            | 
            | 
           162 | 
                   } else {
  | 
        
        
            | 
            | 
           163 | 
                       // Just wait then.
  | 
        
        
            | 
            | 
           164 | 
                       $waittime = $content;
  | 
        
        
            | 
            | 
           165 | 
                   }
  | 
        
        
            | 
            | 
           166 | 
              | 
        
        
            | 
            | 
           167 | 
              | 
        
        
            | 
            | 
           168 | 
                   // Wait until the URL change is executed.
  | 
        
        
            | 
            | 
           169 | 
                   if ($this->running_javascript()) {
  | 
        
        
            | 
            | 
           170 | 
                       $this->getSession()->wait($waittime * 1000);
  | 
        
        
            | 
            | 
           171 | 
              | 
        
        
            | 
            | 
           172 | 
                   } else if (!empty($url)) {
  | 
        
        
            | 
            | 
           173 | 
                       // We redirect directly as we can not wait for an automatic redirection.
  | 
        
        
            | 
            | 
           174 | 
                       $this->getSession()->getDriver()->getClient()->request('GET', $url);
  | 
        
        
            | 
            | 
           175 | 
              | 
        
        
            | 
            | 
           176 | 
                   } else {
  | 
        
        
            | 
            | 
           177 | 
                       // Reload the page if no URL was provided.
  | 
        
        
            | 
            | 
           178 | 
                       $this->getSession()->getDriver()->reload();
  | 
        
        
            | 
            | 
           179 | 
                   }
  | 
        
        
            | 
            | 
           180 | 
               }
  | 
        
        
            | 
            | 
           181 | 
              | 
        
        
            | 
            | 
           182 | 
               /**
  | 
        
        
            | 
            | 
           183 | 
                * Switches to the specified iframe.
  | 
        
        
            | 
            | 
           184 | 
                *
  | 
        
        
            | 
            | 
           185 | 
                * @Given /^I switch to "(?P<iframe_name_string>(?:[^"]|\\")*)" iframe$/
  | 
        
        
            | 
            | 
           186 | 
                * @Given /^I switch to "(?P<iframe_name_string>(?:[^"]|\\")*)" class iframe$/
  | 
        
        
            | 
            | 
           187 | 
                * @param string $name The name of the iframe
  | 
        
        
            | 
            | 
           188 | 
                */
  | 
        
        
            | 
            | 
           189 | 
               public function switch_to_iframe($name) {
  | 
        
        
            | 
            | 
           190 | 
                   // We spin to give time to the iframe to be loaded.
  | 
        
        
            | 
            | 
           191 | 
                   // Using extended timeout as we don't know about which
  | 
        
        
            | 
            | 
           192 | 
                   // kind of iframe will be loaded.
  | 
        
        
            | 
            | 
           193 | 
                   $this->spin(
  | 
        
        
            | 
            | 
           194 | 
                       function($context) use ($name){
  | 
        
        
            | 
            | 
           195 | 
                           $iframe = $context->find('iframe', $name);
  | 
        
        
            | 
            | 
           196 | 
                           if ($iframe->hasAttribute('name')) {
  | 
        
        
            | 
            | 
           197 | 
                               $iframename = $iframe->getAttribute('name');
  | 
        
        
            | 
            | 
           198 | 
                           } else {
  | 
        
        
            | 
            | 
           199 | 
                               if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           200 | 
                                   throw new \coding_exception('iframe must have a name attribute to use the switchTo command.');
  | 
        
        
            | 
            | 
           201 | 
                               }
  | 
        
        
            | 
            | 
           202 | 
                               $iframename = uniqid();
  | 
        
        
            | 
            | 
           203 | 
                               $this->execute_js_on_node($iframe, "{{ELEMENT}}.name = '{$iframename}';");
  | 
        
        
            | 
            | 
           204 | 
                           }
  | 
        
        
            | 
            | 
           205 | 
                           $context->getSession()->switchToIFrame($iframename);
  | 
        
        
            | 
            | 
           206 | 
              | 
        
        
            | 
            | 
           207 | 
                           // If no exception we are done.
  | 
        
        
            | 
            | 
           208 | 
                           return true;
  | 
        
        
            | 
            | 
           209 | 
                       },
  | 
        
        
            | 
            | 
           210 | 
                       behat_base::get_extended_timeout()
  | 
        
        
            | 
            | 
           211 | 
                   );
  | 
        
        
            | 
            | 
           212 | 
               }
  | 
        
        
            | 
            | 
           213 | 
              | 
        
        
            | 
            | 
           214 | 
               /**
  | 
        
        
            | 
            | 
           215 | 
                * Switches to the main Moodle frame.
  | 
        
        
            | 
            | 
           216 | 
                *
  | 
        
        
            | 
            | 
           217 | 
                * @Given /^I switch to the main frame$/
  | 
        
        
            | 
            | 
           218 | 
                */
  | 
        
        
            | 
            | 
           219 | 
               public function switch_to_the_main_frame() {
  | 
        
        
            | 
            | 
           220 | 
                   $this->getSession()->switchToIFrame();
  | 
        
        
            | 
            | 
           221 | 
               }
  | 
        
        
            | 
            | 
           222 | 
              | 
        
        
            | 
            | 
           223 | 
               /**
  | 
        
        
            | 
            | 
           224 | 
                * Switches to the specified window. Useful when interacting with popup windows.
  | 
        
        
            | 
            | 
           225 | 
                *
  | 
        
        
            | 
            | 
           226 | 
                * @Given /^I switch to "(?P<window_name_string>(?:[^"]|\\")*)" (window|tab)$/
  | 
        
        
            | 
            | 
           227 | 
                * @param string $windowname
  | 
        
        
            | 
            | 
           228 | 
                */
  | 
        
        
            | 
            | 
           229 | 
               public function switch_to_window($windowname) {
  | 
        
        
            | 
            | 
           230 | 
                   if ($windowname === self::MAIN_WINDOW_NAME) {
  | 
        
        
            | 
            | 
           231 | 
                       // When switching to the main window normalise the window name to null.
  | 
        
        
            | 
            | 
           232 | 
                       // This is normalised further in the Mink driver to the root window ID.
  | 
        
        
            | 
            | 
           233 | 
                       $windowname = null;
  | 
        
        
            | 
            | 
           234 | 
                   }
  | 
        
        
            | 
            | 
           235 | 
              | 
        
        
            | 
            | 
           236 | 
                   $this->getSession()->switchToWindow($windowname);
  | 
        
        
            | 
            | 
           237 | 
               }
  | 
        
        
            | 
            | 
           238 | 
              | 
        
        
            | 
            | 
           239 | 
               /**
  | 
        
        
            | 
            | 
           240 | 
                * Switches to a second window.
  | 
        
        
            | 
            | 
           241 | 
                *
  | 
        
        
            | 
            | 
           242 | 
                * @Given /^I switch to a second window$/
  | 
        
        
            | 
            | 
           243 | 
                * @throws DriverException If there aren't exactly 2 windows open.
  | 
        
        
            | 
            | 
           244 | 
                */
  | 
        
        
            | 
            | 
           245 | 
               public function switch_to_second_window() {
  | 
        
        
            | 
            | 
           246 | 
                   $names = $this->getSession()->getWindowNames();
  | 
        
        
            | 
            | 
           247 | 
              | 
        
        
            | 
            | 
           248 | 
                   if (count($names) !== 2) {
  | 
        
        
            | 
            | 
           249 | 
                       throw new DriverException('Expected to see 2 windows open, found ' . count($names));
  | 
        
        
            | 
            | 
           250 | 
                   }
  | 
        
        
            | 
            | 
           251 | 
              | 
        
        
            | 
            | 
           252 | 
                   $this->getSession()->switchToWindow($names[1]);
  | 
        
        
            | 
            | 
           253 | 
               }
  | 
        
        
            | 
            | 
           254 | 
              | 
        
        
            | 
            | 
           255 | 
               /**
  | 
        
        
            | 
            | 
           256 | 
                * Switches to the main Moodle window. Useful when you finish interacting with popup windows.
  | 
        
        
            | 
            | 
           257 | 
                *
  | 
        
        
            | 
            | 
           258 | 
                * @Given /^I switch to the main (window|tab)$/
  | 
        
        
            | 
            | 
           259 | 
                */
  | 
        
        
            | 
            | 
           260 | 
               public function switch_to_the_main_window() {
  | 
        
        
            | 
            | 
           261 | 
                   $this->switch_to_window(self::MAIN_WINDOW_NAME);
  | 
        
        
            | 
            | 
           262 | 
               }
  | 
        
        
            | 
            | 
           263 | 
              | 
        
        
            | 
            | 
           264 | 
               /**
  | 
        
        
            | 
            | 
           265 | 
                * Closes all extra windows opened during the navigation.
  | 
        
        
            | 
            | 
           266 | 
                *
  | 
        
        
            | 
            | 
           267 | 
                * This assumes all popups are opened by the main tab and you will now get back.
  | 
        
        
            | 
            | 
           268 | 
                *
  | 
        
        
            | 
            | 
           269 | 
                * @Given /^I close all opened windows$/
  | 
        
        
            | 
            | 
           270 | 
                * @throws DriverException If there aren't exactly 1 tabs open when finish or no javascript running
  | 
        
        
            | 
            | 
           271 | 
                */
  | 
        
        
            | 
            | 
           272 | 
               public function i_close_all_opened_windows() {
  | 
        
        
            | 
            | 
           273 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           274 | 
                       throw new DriverException('Closing windows steps require javascript');
  | 
        
        
            | 
            | 
           275 | 
                   }
  | 
        
        
            | 
            | 
           276 | 
                   $names = $this->getSession()->getWindowNames();
  | 
        
        
            | 
            | 
           277 | 
                   for ($index = 1; $index < count($names); $index ++) {
  | 
        
        
            | 
            | 
           278 | 
                       $this->getSession()->switchToWindow($names[$index]);
  | 
        
        
            | 
            | 
           279 | 
                       $this->execute_script("window.open('', '_self').close();");
  | 
        
        
            | 
            | 
           280 | 
                   }
  | 
        
        
            | 
            | 
           281 | 
                   $names = $this->getSession()->getWindowNames();
  | 
        
        
            | 
            | 
           282 | 
                   if (count($names) !== 1) {
  | 
        
        
            | 
            | 
           283 | 
                       throw new DriverException('Expected to see 1 tabs open, not ' . count($names));
  | 
        
        
            | 
            | 
           284 | 
                   }
  | 
        
        
            | 
            | 
           285 | 
                   $this->getSession()->switchToWindow($names[0]);
  | 
        
        
            | 
            | 
           286 | 
               }
  | 
        
        
            | 
            | 
           287 | 
              | 
        
        
            | 
            | 
           288 | 
               /**
  | 
        
        
           | 11 | 
           efrain | 
           289 | 
                * Wait for an alert to be displayed.
  | 
        
        
            | 
            | 
           290 | 
                *
  | 
        
        
            | 
            | 
           291 | 
                * @return WebDriverAlert
  | 
        
        
            | 
            | 
           292 | 
                */
  | 
        
        
            | 
            | 
           293 | 
               public function wait_for_alert(): WebDriverAlert {
  | 
        
        
            | 
            | 
           294 | 
                   $webdriver = $this->getSession()->getDriver()->getWebdriver();
  | 
        
        
            | 
            | 
           295 | 
                   $webdriver->wait()->until(WebDriverExpectedCondition::alertIsPresent());
  | 
        
        
            | 
            | 
           296 | 
              | 
        
        
            | 
            | 
           297 | 
                   return $webdriver->switchTo()->alert();
  | 
        
        
            | 
            | 
           298 | 
               }
  | 
        
        
            | 
            | 
           299 | 
              | 
        
        
            | 
            | 
           300 | 
               /**
  | 
        
        
           | 1 | 
           efrain | 
           301 | 
                * Accepts the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
  | 
        
        
            | 
            | 
           302 | 
                * @Given /^I accept the currently displayed dialog$/
  | 
        
        
            | 
            | 
           303 | 
                */
  | 
        
        
            | 
            | 
           304 | 
               public function accept_currently_displayed_alert_dialog() {
  | 
        
        
           | 11 | 
           efrain | 
           305 | 
                   $alert = $this->wait_for_alert();
  | 
        
        
            | 
            | 
           306 | 
                   $alert->accept();
  | 
        
        
           | 1 | 
           efrain | 
           307 | 
               }
  | 
        
        
            | 
            | 
           308 | 
              | 
        
        
            | 
            | 
           309 | 
               /**
  | 
        
        
            | 
            | 
           310 | 
                * Dismisses the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
  | 
        
        
            | 
            | 
           311 | 
                * @Given /^I dismiss the currently displayed dialog$/
  | 
        
        
            | 
            | 
           312 | 
                */
  | 
        
        
            | 
            | 
           313 | 
               public function dismiss_currently_displayed_alert_dialog() {
  | 
        
        
           | 11 | 
           efrain | 
           314 | 
                   $alert = $this->wait_for_alert();
  | 
        
        
            | 
            | 
           315 | 
                   $alert->dismiss();
  | 
        
        
           | 1 | 
           efrain | 
           316 | 
               }
  | 
        
        
            | 
            | 
           317 | 
              | 
        
        
            | 
            | 
           318 | 
               /**
  | 
        
        
            | 
            | 
           319 | 
                * Clicks link with specified id|title|alt|text.
  | 
        
        
            | 
            | 
           320 | 
                *
  | 
        
        
            | 
            | 
           321 | 
                * @When /^I follow "(?P<link_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           322 | 
                * @throws ElementNotFoundException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           323 | 
                * @param string $link
  | 
        
        
            | 
            | 
           324 | 
                */
  | 
        
        
            | 
            | 
           325 | 
               public function click_link($link) {
  | 
        
        
            | 
            | 
           326 | 
                   $linknode = $this->find_link($link);
  | 
        
        
            | 
            | 
           327 | 
                   $linknode->click();
  | 
        
        
            | 
            | 
           328 | 
               }
  | 
        
        
            | 
            | 
           329 | 
              | 
        
        
            | 
            | 
           330 | 
               /**
  | 
        
        
            | 
            | 
           331 | 
                * Waits X seconds. Required after an action that requires data from an AJAX request.
  | 
        
        
            | 
            | 
           332 | 
                *
  | 
        
        
            | 
            | 
           333 | 
                * @Then /^I wait "(?P<seconds_number>\d+)" seconds$/
  | 
        
        
            | 
            | 
           334 | 
                * @param int $seconds
  | 
        
        
            | 
            | 
           335 | 
                */
  | 
        
        
            | 
            | 
           336 | 
               public function i_wait_seconds($seconds) {
  | 
        
        
            | 
            | 
           337 | 
                   if ($this->running_javascript()) {
  | 
        
        
            | 
            | 
           338 | 
                       $this->getSession()->wait($seconds * 1000);
  | 
        
        
            | 
            | 
           339 | 
                   } else {
  | 
        
        
            | 
            | 
           340 | 
                       sleep($seconds);
  | 
        
        
            | 
            | 
           341 | 
                   }
  | 
        
        
            | 
            | 
           342 | 
               }
  | 
        
        
            | 
            | 
           343 | 
              | 
        
        
            | 
            | 
           344 | 
               /**
  | 
        
        
            | 
            | 
           345 | 
                * Waits until the page is completely loaded. This step is auto-executed after every step.
  | 
        
        
            | 
            | 
           346 | 
                *
  | 
        
        
            | 
            | 
           347 | 
                * @Given /^I wait until the page is ready$/
  | 
        
        
            | 
            | 
           348 | 
                */
  | 
        
        
            | 
            | 
           349 | 
               public function wait_until_the_page_is_ready() {
  | 
        
        
            | 
            | 
           350 | 
              | 
        
        
            | 
            | 
           351 | 
                   // No need to wait if not running JS.
  | 
        
        
            | 
            | 
           352 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           353 | 
                       return;
  | 
        
        
            | 
            | 
           354 | 
                   }
  | 
        
        
            | 
            | 
           355 | 
              | 
        
        
            | 
            | 
           356 | 
                   $this->getSession()->wait(self::get_timeout() * 1000, self::PAGE_READY_JS);
  | 
        
        
            | 
            | 
           357 | 
               }
  | 
        
        
            | 
            | 
           358 | 
              | 
        
        
            | 
            | 
           359 | 
               /**
  | 
        
        
            | 
            | 
           360 | 
                * Waits until the provided element selector exists in the DOM
  | 
        
        
            | 
            | 
           361 | 
                *
  | 
        
        
            | 
            | 
           362 | 
                * Using the protected method as this method will be usually
  | 
        
        
            | 
            | 
           363 | 
                * called by other methods which are not returning a set of
  | 
        
        
            | 
            | 
           364 | 
                * steps and performs the actions directly, so it would not
  | 
        
        
            | 
            | 
           365 | 
                * be executed if it returns another step.
  | 
        
        
            | 
            | 
           366 | 
              | 
        
        
            | 
            | 
           367 | 
                * @Given /^I wait until "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" exists$/
  | 
        
        
            | 
            | 
           368 | 
                * @param string $element
  | 
        
        
            | 
            | 
           369 | 
                * @param string $selector
  | 
        
        
            | 
            | 
           370 | 
                * @return void
  | 
        
        
            | 
            | 
           371 | 
                */
  | 
        
        
            | 
            | 
           372 | 
               public function wait_until_exists($element, $selectortype) {
  | 
        
        
            | 
            | 
           373 | 
                   $this->ensure_element_exists($element, $selectortype);
  | 
        
        
            | 
            | 
           374 | 
               }
  | 
        
        
            | 
            | 
           375 | 
              | 
        
        
            | 
            | 
           376 | 
               /**
  | 
        
        
            | 
            | 
           377 | 
                * Waits until the provided element does not exist in the DOM
  | 
        
        
            | 
            | 
           378 | 
                *
  | 
        
        
            | 
            | 
           379 | 
                * Using the protected method as this method will be usually
  | 
        
        
            | 
            | 
           380 | 
                * called by other methods which are not returning a set of
  | 
        
        
            | 
            | 
           381 | 
                * steps and performs the actions directly, so it would not
  | 
        
        
            | 
            | 
           382 | 
                * be executed if it returns another step.
  | 
        
        
            | 
            | 
           383 | 
              | 
        
        
            | 
            | 
           384 | 
                * @Given /^I wait until "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" does not exist$/
  | 
        
        
            | 
            | 
           385 | 
                * @param string $element
  | 
        
        
            | 
            | 
           386 | 
                * @param string $selector
  | 
        
        
            | 
            | 
           387 | 
                * @return void
  | 
        
        
            | 
            | 
           388 | 
                */
  | 
        
        
            | 
            | 
           389 | 
               public function wait_until_does_not_exists($element, $selectortype) {
  | 
        
        
            | 
            | 
           390 | 
                   $this->ensure_element_does_not_exist($element, $selectortype);
  | 
        
        
            | 
            | 
           391 | 
               }
  | 
        
        
            | 
            | 
           392 | 
              | 
        
        
            | 
            | 
           393 | 
               /**
  | 
        
        
            | 
            | 
           394 | 
                * Generic mouse over action. Mouse over a element of the specified type.
  | 
        
        
            | 
            | 
           395 | 
                *
  | 
        
        
            | 
            | 
           396 | 
                * @When /^I hover "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           397 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           398 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           399 | 
                */
  | 
        
        
            | 
            | 
           400 | 
               public function i_hover($element, $selectortype) {
  | 
        
        
            | 
            | 
           401 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
            | 
            | 
           402 | 
                   $node = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           403 | 
                   $this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
  | 
        
        
            | 
            | 
           404 | 
                   $node->mouseOver();
  | 
        
        
            | 
            | 
           405 | 
               }
  | 
        
        
            | 
            | 
           406 | 
              | 
        
        
            | 
            | 
           407 | 
               /**
  | 
        
        
            | 
            | 
           408 | 
                * Generic mouse over action. Mouse over a element of the specified type.
  | 
        
        
            | 
            | 
           409 | 
                *
  | 
        
        
            | 
            | 
           410 | 
                * @When I hover over the :element :selectortype in the :containerelement :containerselectortype
  | 
        
        
            | 
            | 
           411 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           412 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           413 | 
                * @param string $containerelement Element we look for
  | 
        
        
            | 
            | 
           414 | 
                * @param string $containerselectortype The type of what we look for
  | 
        
        
            | 
            | 
           415 | 
                */
  | 
        
        
            | 
            | 
           416 | 
               public function i_hover_in_the(string $element, $selectortype, string $containerelement, $containerselectortype): void {
  | 
        
        
            | 
            | 
           417 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
            | 
            | 
           418 | 
                   $node = $this->get_node_in_container($selectortype, $element, $containerselectortype, $containerelement);
  | 
        
        
            | 
            | 
           419 | 
                   $this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
  | 
        
        
            | 
            | 
           420 | 
                   $node->mouseOver();
  | 
        
        
            | 
            | 
           421 | 
               }
  | 
        
        
            | 
            | 
           422 | 
              | 
        
        
            | 
            | 
           423 | 
               /**
  | 
        
        
            | 
            | 
           424 | 
                * Generic click action. Click on the element of the specified type.
  | 
        
        
            | 
            | 
           425 | 
                *
  | 
        
        
            | 
            | 
           426 | 
                * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           427 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           428 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           429 | 
                */
  | 
        
        
            | 
            | 
           430 | 
               public function i_click_on($element, $selectortype) {
  | 
        
        
            | 
            | 
           431 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
           | 11 | 
           efrain | 
           432 | 
                   $this->get_selected_node($selectortype, $element)->click();
  | 
        
        
           | 1 | 
           efrain | 
           433 | 
               }
  | 
        
        
            | 
            | 
           434 | 
              | 
        
        
            | 
            | 
           435 | 
               /**
  | 
        
        
            | 
            | 
           436 | 
                * Sets the focus and takes away the focus from an element, generating blur JS event.
  | 
        
        
            | 
            | 
           437 | 
                *
  | 
        
        
            | 
            | 
           438 | 
                * @When /^I take focus off "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           439 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           440 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           441 | 
                */
  | 
        
        
            | 
            | 
           442 | 
               public function i_take_focus_off_field($element, $selectortype) {
  | 
        
        
            | 
            | 
           443 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           444 | 
                       throw new ExpectationException('Can\'t take focus off from "' . $element . '" in non-js mode', $this->getSession());
  | 
        
        
            | 
            | 
           445 | 
                   }
  | 
        
        
            | 
            | 
           446 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
            | 
            | 
           447 | 
                   $node = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           448 | 
                   $this->ensure_node_is_visible($node);
  | 
        
        
            | 
            | 
           449 | 
              | 
        
        
            | 
            | 
           450 | 
                   // Ensure element is focused before taking it off.
  | 
        
        
            | 
            | 
           451 | 
                   $node->focus();
  | 
        
        
            | 
            | 
           452 | 
                   $node->blur();
  | 
        
        
            | 
            | 
           453 | 
               }
  | 
        
        
            | 
            | 
           454 | 
              | 
        
        
            | 
            | 
           455 | 
               /**
  | 
        
        
            | 
            | 
           456 | 
                * Clicks the specified element and confirms the expected dialogue.
  | 
        
        
            | 
            | 
           457 | 
                *
  | 
        
        
            | 
            | 
           458 | 
                * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" confirming the dialogue$/
  | 
        
        
            | 
            | 
           459 | 
                * @throws ElementNotFoundException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           460 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           461 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           462 | 
                */
  | 
        
        
            | 
            | 
           463 | 
               public function i_click_on_confirming_the_dialogue($element, $selectortype) {
  | 
        
        
            | 
            | 
           464 | 
                   $this->i_click_on($element, $selectortype);
  | 
        
        
           | 1441 | 
           ariadna | 
           465 | 
                   $this->execute([self::class, 'accept_currently_displayed_alert_dialog'], []);
  | 
        
        
           | 1 | 
           efrain | 
           466 | 
                   $this->wait_until_the_page_is_ready();
  | 
        
        
            | 
            | 
           467 | 
               }
  | 
        
        
            | 
            | 
           468 | 
              | 
        
        
            | 
            | 
           469 | 
               /**
  | 
        
        
            | 
            | 
           470 | 
                * Clicks the specified element and dismissing the expected dialogue.
  | 
        
        
            | 
            | 
           471 | 
                *
  | 
        
        
            | 
            | 
           472 | 
                * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" dismissing the dialogue$/
  | 
        
        
            | 
            | 
           473 | 
                * @throws ElementNotFoundException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           474 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           475 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           476 | 
                */
  | 
        
        
            | 
            | 
           477 | 
               public function i_click_on_dismissing_the_dialogue($element, $selectortype) {
  | 
        
        
            | 
            | 
           478 | 
                   $this->i_click_on($element, $selectortype);
  | 
        
        
           | 1441 | 
           ariadna | 
           479 | 
                   $this->execute([self::class, 'dismiss_currently_displayed_alert_dialog'], []);
  | 
        
        
           | 1 | 
           efrain | 
           480 | 
                   $this->wait_until_the_page_is_ready();
  | 
        
        
            | 
            | 
           481 | 
               }
  | 
        
        
            | 
            | 
           482 | 
              | 
        
        
            | 
            | 
           483 | 
               /**
  | 
        
        
            | 
            | 
           484 | 
                * Click on the element of the specified type which is located inside the second element.
  | 
        
        
            | 
            | 
           485 | 
                *
  | 
        
        
            | 
            | 
           486 | 
                * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           487 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           488 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           489 | 
                * @param string $nodeelement Element we look in
  | 
        
        
            | 
            | 
           490 | 
                * @param string $nodeselectortype The type of selector where we look in
  | 
        
        
            | 
            | 
           491 | 
                */
  | 
        
        
            | 
            | 
           492 | 
               public function i_click_on_in_the($element, $selectortype, $nodeelement, $nodeselectortype) {
  | 
        
        
            | 
            | 
           493 | 
                   $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
  | 
        
        
            | 
            | 
           494 | 
                   $node->click();
  | 
        
        
            | 
            | 
           495 | 
               }
  | 
        
        
            | 
            | 
           496 | 
              | 
        
        
            | 
            | 
           497 | 
               /**
  | 
        
        
            | 
            | 
           498 | 
                * Click on the element with some modifier key pressed (alt, shift, meta or control).
  | 
        
        
            | 
            | 
           499 | 
                *
  | 
        
        
            | 
            | 
           500 | 
                * It is important to note that not all HTML elements are compatible with this step because
  | 
        
        
            | 
            | 
           501 | 
                * the webdriver limitations. For example, alt click on checkboxes with a visible label will
  | 
        
        
            | 
            | 
           502 | 
                * produce a normal checkbox click without the modifier.
  | 
        
        
            | 
            | 
           503 | 
                *
  | 
        
        
            | 
            | 
           504 | 
                * @When I :modifier click on :element :selectortype in the :nodeelement :nodeselectortype
  | 
        
        
            | 
            | 
           505 | 
                * @param string $modifier the extra modifier to press (for example, alt+shift or shift)
  | 
        
        
            | 
            | 
           506 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           507 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           508 | 
                * @param string $nodeelement Element we look in
  | 
        
        
            | 
            | 
           509 | 
                * @param string $nodeselectortype The type of selector where we look in
  | 
        
        
            | 
            | 
           510 | 
                */
  | 
        
        
            | 
            | 
           511 | 
               public function i_key_click_on_in_the($modifier, $element, $selectortype, $nodeelement, $nodeselectortype) {
  | 
        
        
            | 
            | 
           512 | 
                   behat_base::require_javascript_in_session($this->getSession());
  | 
        
        
            | 
            | 
           513 | 
              | 
        
        
            | 
            | 
           514 | 
                   $key = null;
  | 
        
        
            | 
            | 
           515 | 
                   switch (strtoupper(trim($modifier))) {
  | 
        
        
            | 
            | 
           516 | 
                       case '':
  | 
        
        
            | 
            | 
           517 | 
                           break;
  | 
        
        
            | 
            | 
           518 | 
                       case 'SHIFT':
  | 
        
        
            | 
            | 
           519 | 
                           $key = behat_keys::SHIFT;
  | 
        
        
            | 
            | 
           520 | 
                           break;
  | 
        
        
            | 
            | 
           521 | 
                       case 'CTRL':
  | 
        
        
            | 
            | 
           522 | 
                           $key = behat_keys::CONTROL;
  | 
        
        
            | 
            | 
           523 | 
                           break;
  | 
        
        
            | 
            | 
           524 | 
                       case 'ALT':
  | 
        
        
            | 
            | 
           525 | 
                           $key = behat_keys::ALT;
  | 
        
        
            | 
            | 
           526 | 
                           break;
  | 
        
        
            | 
            | 
           527 | 
                       case 'META':
  | 
        
        
            | 
            | 
           528 | 
                           $key = behat_keys::META;
  | 
        
        
            | 
            | 
           529 | 
                           break;
  | 
        
        
            | 
            | 
           530 | 
                       default:
  | 
        
        
            | 
            | 
           531 | 
                           throw new \coding_exception("Unknown modifier key '$modifier'}");
  | 
        
        
            | 
            | 
           532 | 
                   }
  | 
        
        
            | 
            | 
           533 | 
              | 
        
        
            | 
            | 
           534 | 
                   $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
  | 
        
        
            | 
            | 
           535 | 
              | 
        
        
            | 
            | 
           536 | 
                   // KeyUP and KeyDown require the element to be displayed in the current window.
  | 
        
        
            | 
            | 
           537 | 
                   $this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
  | 
        
        
            | 
            | 
           538 | 
                   $node->keyDown($key);
  | 
        
        
            | 
            | 
           539 | 
                   $node->click();
  | 
        
        
            | 
            | 
           540 | 
                   // Any click action can move the scroll. Ensure the element is still displayed.
  | 
        
        
            | 
            | 
           541 | 
                   $this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
  | 
        
        
            | 
            | 
           542 | 
                   $node->keyUp($key);
  | 
        
        
            | 
            | 
           543 | 
               }
  | 
        
        
            | 
            | 
           544 | 
              | 
        
        
            | 
            | 
           545 | 
               /**
  | 
        
        
            | 
            | 
           546 | 
                * Drags and drops the specified element to the specified container. This step does not work in all the browsers, consider it experimental.
  | 
        
        
            | 
            | 
           547 | 
                *
  | 
        
        
            | 
            | 
           548 | 
                * The steps definitions calling this step as part of them should
  | 
        
        
            | 
            | 
           549 | 
                * manage the wait times by themselves as the times and when the
  | 
        
        
            | 
            | 
           550 | 
                * waits should be done depends on what is being dragged & dropper.
  | 
        
        
            | 
            | 
           551 | 
                *
  | 
        
        
            | 
            | 
           552 | 
                * @Given /^I drag "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" and I drop it in "(?P<container_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           553 | 
                * @param string $element
  | 
        
        
            | 
            | 
           554 | 
                * @param string $selectortype
  | 
        
        
            | 
            | 
           555 | 
                * @param string $containerelement
  | 
        
        
            | 
            | 
           556 | 
                * @param string $containerselectortype
  | 
        
        
            | 
            | 
           557 | 
                */
  | 
        
        
            | 
            | 
           558 | 
               public function i_drag_and_i_drop_it_in($source, $sourcetype, $target, $targettype) {
  | 
        
        
            | 
            | 
           559 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           560 | 
                       throw new DriverException('Drag and drop steps require javascript');
  | 
        
        
            | 
            | 
           561 | 
                   }
  | 
        
        
            | 
            | 
           562 | 
              | 
        
        
            | 
            | 
           563 | 
                   $source = $this->find($sourcetype, $source);
  | 
        
        
            | 
            | 
           564 | 
                   $target = $this->find($targettype, $target);
  | 
        
        
            | 
            | 
           565 | 
              | 
        
        
            | 
            | 
           566 | 
                   if (!$source->isVisible()) {
  | 
        
        
            | 
            | 
           567 | 
                       throw new ExpectationException("'{$source}' '{$sourcetype}' is not visible", $this->getSession());
  | 
        
        
            | 
            | 
           568 | 
                   }
  | 
        
        
            | 
            | 
           569 | 
                   if (!$target->isVisible()) {
  | 
        
        
            | 
            | 
           570 | 
                       throw new ExpectationException("'{$target}' '{$targettype}' is not visible", $this->getSession());
  | 
        
        
            | 
            | 
           571 | 
                   }
  | 
        
        
            | 
            | 
           572 | 
              | 
        
        
            | 
            | 
           573 | 
                   $this->getSession()->getDriver()->dragTo($source->getXpath(), $target->getXpath());
  | 
        
        
            | 
            | 
           574 | 
               }
  | 
        
        
            | 
            | 
           575 | 
              | 
        
        
            | 
            | 
           576 | 
               /**
  | 
        
        
            | 
            | 
           577 | 
                * Checks, that the specified element is visible. Only available in tests using Javascript.
  | 
        
        
            | 
            | 
           578 | 
                *
  | 
        
        
            | 
            | 
           579 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" should be visible$/
  | 
        
        
            | 
            | 
           580 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           581 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           582 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           583 | 
                * @param string $element
  | 
        
        
            | 
            | 
           584 | 
                * @param string $selectortype
  | 
        
        
            | 
            | 
           585 | 
                * @return void
  | 
        
        
            | 
            | 
           586 | 
                */
  | 
        
        
            | 
            | 
           587 | 
               public function should_be_visible($element, $selectortype) {
  | 
        
        
            | 
            | 
           588 | 
              | 
        
        
            | 
            | 
           589 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           590 | 
                       throw new DriverException('Visible checks are disabled in scenarios without Javascript support');
  | 
        
        
            | 
            | 
           591 | 
                   }
  | 
        
        
            | 
            | 
           592 | 
              | 
        
        
            | 
            | 
           593 | 
                   $node = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           594 | 
                   if (!$node->isVisible()) {
  | 
        
        
            | 
            | 
           595 | 
                       throw new ExpectationException('"' . $element . '" "' . $selectortype . '" is not visible', $this->getSession());
  | 
        
        
            | 
            | 
           596 | 
                   }
  | 
        
        
            | 
            | 
           597 | 
               }
  | 
        
        
            | 
            | 
           598 | 
              | 
        
        
            | 
            | 
           599 | 
               /**
  | 
        
        
            | 
            | 
           600 | 
                * Checks, that the existing element is not visible. Only available in tests using Javascript.
  | 
        
        
            | 
            | 
           601 | 
                *
  | 
        
        
            | 
            | 
           602 | 
                * As a "not" method, it's performance could not be good, but in this
  | 
        
        
            | 
            | 
           603 | 
                * case the performance is good because the element must exist,
  | 
        
        
            | 
            | 
           604 | 
                * otherwise there would be a ElementNotFoundException, also here we are
  | 
        
        
            | 
            | 
           605 | 
                * not spinning until the element is visible.
  | 
        
        
            | 
            | 
           606 | 
                *
  | 
        
        
            | 
            | 
           607 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" should not be visible$/
  | 
        
        
            | 
            | 
           608 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           609 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           610 | 
                * @param string $element
  | 
        
        
            | 
            | 
           611 | 
                * @param string $selectortype
  | 
        
        
            | 
            | 
           612 | 
                * @return void
  | 
        
        
            | 
            | 
           613 | 
                */
  | 
        
        
            | 
            | 
           614 | 
               public function should_not_be_visible($element, $selectortype) {
  | 
        
        
            | 
            | 
           615 | 
              | 
        
        
            | 
            | 
           616 | 
                   try {
  | 
        
        
            | 
            | 
           617 | 
                       $this->should_be_visible($element, $selectortype);
  | 
        
        
            | 
            | 
           618 | 
                   } catch (ExpectationException $e) {
  | 
        
        
            | 
            | 
           619 | 
                       // All as expected.
  | 
        
        
            | 
            | 
           620 | 
                       return;
  | 
        
        
            | 
            | 
           621 | 
                   }
  | 
        
        
            | 
            | 
           622 | 
                   throw new ExpectationException('"' . $element . '" "' . $selectortype . '" is visible', $this->getSession());
  | 
        
        
            | 
            | 
           623 | 
               }
  | 
        
        
            | 
            | 
           624 | 
              | 
        
        
            | 
            | 
           625 | 
               /**
  | 
        
        
            | 
            | 
           626 | 
                * Checks, that the specified element is visible inside the specified container. Only available in tests using Javascript.
  | 
        
        
            | 
            | 
           627 | 
                *
  | 
        
        
            | 
            | 
           628 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" should be visible$/
  | 
        
        
            | 
            | 
           629 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           630 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           631 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           632 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           633 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           634 | 
                * @param string $nodeelement Element we look in
  | 
        
        
            | 
            | 
           635 | 
                * @param string $nodeselectortype The type of selector where we look in
  | 
        
        
            | 
            | 
           636 | 
                */
  | 
        
        
            | 
            | 
           637 | 
               public function in_the_should_be_visible($element, $selectortype, $nodeelement, $nodeselectortype) {
  | 
        
        
            | 
            | 
           638 | 
              | 
        
        
            | 
            | 
           639 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           640 | 
                       throw new DriverException('Visible checks are disabled in scenarios without Javascript support');
  | 
        
        
            | 
            | 
           641 | 
                   }
  | 
        
        
            | 
            | 
           642 | 
              | 
        
        
            | 
            | 
           643 | 
                   $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
  | 
        
        
            | 
            | 
           644 | 
                   if (!$node->isVisible()) {
  | 
        
        
            | 
            | 
           645 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           646 | 
                           '"' . $element . '" "' . $selectortype . '" in the "' . $nodeelement . '" "' . $nodeselectortype . '" is not visible',
  | 
        
        
            | 
            | 
           647 | 
                           $this->getSession()
  | 
        
        
            | 
            | 
           648 | 
                       );
  | 
        
        
            | 
            | 
           649 | 
                   }
  | 
        
        
            | 
            | 
           650 | 
               }
  | 
        
        
            | 
            | 
           651 | 
              | 
        
        
            | 
            | 
           652 | 
               /**
  | 
        
        
            | 
            | 
           653 | 
                * Checks, that the existing element is not visible inside the existing container. Only available in tests using Javascript.
  | 
        
        
            | 
            | 
           654 | 
                *
  | 
        
        
            | 
            | 
           655 | 
                * As a "not" method, it's performance could not be good, but in this
  | 
        
        
            | 
            | 
           656 | 
                * case the performance is good because the element must exist,
  | 
        
        
            | 
            | 
           657 | 
                * otherwise there would be a ElementNotFoundException, also here we are
  | 
        
        
            | 
            | 
           658 | 
                * not spinning until the element is visible.
  | 
        
        
            | 
            | 
           659 | 
                *
  | 
        
        
            | 
            | 
           660 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" should not be visible$/
  | 
        
        
            | 
            | 
           661 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           662 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           663 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           664 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           665 | 
                * @param string $nodeelement Element we look in
  | 
        
        
            | 
            | 
           666 | 
                * @param string $nodeselectortype The type of selector where we look in
  | 
        
        
            | 
            | 
           667 | 
                */
  | 
        
        
            | 
            | 
           668 | 
               public function in_the_should_not_be_visible($element, $selectortype, $nodeelement, $nodeselectortype) {
  | 
        
        
            | 
            | 
           669 | 
              | 
        
        
            | 
            | 
           670 | 
                   try {
  | 
        
        
            | 
            | 
           671 | 
                       $this->in_the_should_be_visible($element, $selectortype, $nodeelement, $nodeselectortype);
  | 
        
        
            | 
            | 
           672 | 
                   } catch (ExpectationException $e) {
  | 
        
        
            | 
            | 
           673 | 
                       // All as expected.
  | 
        
        
            | 
            | 
           674 | 
                       return;
  | 
        
        
            | 
            | 
           675 | 
                   }
  | 
        
        
            | 
            | 
           676 | 
                   throw new ExpectationException(
  | 
        
        
            | 
            | 
           677 | 
                       '"' . $element . '" "' . $selectortype . '" in the "' . $nodeelement . '" "' . $nodeselectortype . '" is visible',
  | 
        
        
            | 
            | 
           678 | 
                       $this->getSession()
  | 
        
        
            | 
            | 
           679 | 
                   );
  | 
        
        
            | 
            | 
           680 | 
               }
  | 
        
        
            | 
            | 
           681 | 
              | 
        
        
            | 
            | 
           682 | 
               /**
  | 
        
        
            | 
            | 
           683 | 
                * Checks, that page contains specified text. It also checks if the text is visible when running Javascript tests.
  | 
        
        
            | 
            | 
           684 | 
                *
  | 
        
        
            | 
            | 
           685 | 
                * @Then /^I should see "(?P<text_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           686 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           687 | 
                * @param string $text
  | 
        
        
            | 
            | 
           688 | 
                */
  | 
        
        
            | 
            | 
           689 | 
               public function assert_page_contains_text($text) {
  | 
        
        
            | 
            | 
           690 | 
              | 
        
        
            | 
            | 
           691 | 
                   // Looking for all the matching nodes without any other descendant matching the
  | 
        
        
            | 
            | 
           692 | 
                   // same xpath (we are using contains(., ....).
  | 
        
        
            | 
            | 
           693 | 
                   $xpathliteral = behat_context_helper::escape($text);
  | 
        
        
            | 
            | 
           694 | 
                   $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" .
  | 
        
        
            | 
            | 
           695 | 
                       "[count(descendant::*[contains(., $xpathliteral)]) = 0]";
  | 
        
        
            | 
            | 
           696 | 
              | 
        
        
            | 
            | 
           697 | 
                   try {
  | 
        
        
            | 
            | 
           698 | 
                       $nodes = $this->find_all('xpath', $xpath);
  | 
        
        
            | 
            | 
           699 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           700 | 
                       throw new ExpectationException('"' . $text . '" text was not found in the page', $this->getSession());
  | 
        
        
            | 
            | 
           701 | 
                   }
  | 
        
        
            | 
            | 
           702 | 
              | 
        
        
            | 
            | 
           703 | 
                   // If we are not running javascript we have enough with the
  | 
        
        
            | 
            | 
           704 | 
                   // element existing as we can't check if it is visible.
  | 
        
        
            | 
            | 
           705 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           706 | 
                       return;
  | 
        
        
            | 
            | 
           707 | 
                   }
  | 
        
        
            | 
            | 
           708 | 
              | 
        
        
            | 
            | 
           709 | 
                   // We spin as we don't have enough checking that the element is there, we
  | 
        
        
            | 
            | 
           710 | 
                   // should also ensure that the element is visible. Using microsleep as this
  | 
        
        
            | 
            | 
           711 | 
                   // is a repeated step and global performance is important.
  | 
        
        
            | 
            | 
           712 | 
                   $this->spin(
  | 
        
        
            | 
            | 
           713 | 
                       function($context, $args) {
  | 
        
        
            | 
            | 
           714 | 
              | 
        
        
            | 
            | 
           715 | 
                           foreach ($args['nodes'] as $node) {
  | 
        
        
            | 
            | 
           716 | 
                               if ($node->isVisible()) {
  | 
        
        
            | 
            | 
           717 | 
                                   return true;
  | 
        
        
            | 
            | 
           718 | 
                               }
  | 
        
        
            | 
            | 
           719 | 
                           }
  | 
        
        
            | 
            | 
           720 | 
              | 
        
        
            | 
            | 
           721 | 
                           // If non of the nodes is visible we loop again.
  | 
        
        
            | 
            | 
           722 | 
                           throw new ExpectationException('"' . $args['text'] . '" text was found but was not visible', $context->getSession());
  | 
        
        
            | 
            | 
           723 | 
                       },
  | 
        
        
            | 
            | 
           724 | 
                       array('nodes' => $nodes, 'text' => $text),
  | 
        
        
            | 
            | 
           725 | 
                       false,
  | 
        
        
            | 
            | 
           726 | 
                       false,
  | 
        
        
            | 
            | 
           727 | 
                       true
  | 
        
        
            | 
            | 
           728 | 
                   );
  | 
        
        
            | 
            | 
           729 | 
              | 
        
        
            | 
            | 
           730 | 
               }
  | 
        
        
            | 
            | 
           731 | 
              | 
        
        
            | 
            | 
           732 | 
               /**
  | 
        
        
            | 
            | 
           733 | 
                * Checks, that page doesn't contain specified text. When running Javascript tests it also considers that texts may be hidden.
  | 
        
        
            | 
            | 
           734 | 
                *
  | 
        
        
            | 
            | 
           735 | 
                * @Then /^I should not see "(?P<text_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           736 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           737 | 
                * @param string $text
  | 
        
        
            | 
            | 
           738 | 
                */
  | 
        
        
            | 
            | 
           739 | 
               public function assert_page_not_contains_text($text) {
  | 
        
        
            | 
            | 
           740 | 
              | 
        
        
            | 
            | 
           741 | 
                   // Looking for all the matching nodes without any other descendant matching the
  | 
        
        
            | 
            | 
           742 | 
                   // same xpath (we are using contains(., ....).
  | 
        
        
            | 
            | 
           743 | 
                   $xpathliteral = behat_context_helper::escape($text);
  | 
        
        
            | 
            | 
           744 | 
                   $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" .
  | 
        
        
            | 
            | 
           745 | 
                       "[count(descendant::*[contains(., $xpathliteral)]) = 0]";
  | 
        
        
            | 
            | 
           746 | 
              | 
        
        
            | 
            | 
           747 | 
                   // We should wait a while to ensure that the page is not still loading elements.
  | 
        
        
            | 
            | 
           748 | 
                   // Waiting less than self::get_timeout() as we already waited for the DOM to be ready and
  | 
        
        
            | 
            | 
           749 | 
                   // all JS to be executed.
  | 
        
        
            | 
            | 
           750 | 
                   try {
  | 
        
        
            | 
            | 
           751 | 
                       $nodes = $this->find_all('xpath', $xpath, false, false, self::get_reduced_timeout());
  | 
        
        
            | 
            | 
           752 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           753 | 
                       // All ok.
  | 
        
        
            | 
            | 
           754 | 
                       return;
  | 
        
        
            | 
            | 
           755 | 
                   }
  | 
        
        
            | 
            | 
           756 | 
              | 
        
        
            | 
            | 
           757 | 
                   // If we are not running javascript we have enough with the
  | 
        
        
            | 
            | 
           758 | 
                   // element existing as we can't check if it is hidden.
  | 
        
        
            | 
            | 
           759 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           760 | 
                       throw new ExpectationException('"' . $text . '" text was found in the page', $this->getSession());
  | 
        
        
            | 
            | 
           761 | 
                   }
  | 
        
        
            | 
            | 
           762 | 
              | 
        
        
            | 
            | 
           763 | 
                   // If the element is there we should be sure that it is not visible.
  | 
        
        
            | 
            | 
           764 | 
                   $this->spin(
  | 
        
        
            | 
            | 
           765 | 
                       function($context, $args) {
  | 
        
        
            | 
            | 
           766 | 
              | 
        
        
            | 
            | 
           767 | 
                           foreach ($args['nodes'] as $node) {
  | 
        
        
            | 
            | 
           768 | 
                               // If element is removed from dom, then just exit.
  | 
        
        
            | 
            | 
           769 | 
                               try {
  | 
        
        
            | 
            | 
           770 | 
                                   // If element is visible then throw exception, so we keep spinning.
  | 
        
        
            | 
            | 
           771 | 
                                   if ($node->isVisible()) {
  | 
        
        
            | 
            | 
           772 | 
                                       throw new ExpectationException('"' . $args['text'] . '" text was found in the page',
  | 
        
        
            | 
            | 
           773 | 
                                           $context->getSession());
  | 
        
        
            | 
            | 
           774 | 
                                   }
  | 
        
        
            | 
            | 
           775 | 
                               } catch (NoSuchElementException $e) {
  | 
        
        
            | 
            | 
           776 | 
                                   // Do nothing just return, as element is no more on page.
  | 
        
        
            | 
            | 
           777 | 
                                   return true;
  | 
        
        
            | 
            | 
           778 | 
                               } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           779 | 
                                   // Do nothing just return, as element is no more on page.
  | 
        
        
            | 
            | 
           780 | 
                                   return true;
  | 
        
        
            | 
            | 
           781 | 
                               }
  | 
        
        
            | 
            | 
           782 | 
                           }
  | 
        
        
            | 
            | 
           783 | 
              | 
        
        
            | 
            | 
           784 | 
                           // If non of the found nodes is visible we consider that the text is not visible.
  | 
        
        
            | 
            | 
           785 | 
                           return true;
  | 
        
        
            | 
            | 
           786 | 
                       },
  | 
        
        
            | 
            | 
           787 | 
                       array('nodes' => $nodes, 'text' => $text),
  | 
        
        
            | 
            | 
           788 | 
                       behat_base::get_reduced_timeout(),
  | 
        
        
            | 
            | 
           789 | 
                       false,
  | 
        
        
            | 
            | 
           790 | 
                       true
  | 
        
        
            | 
            | 
           791 | 
                   );
  | 
        
        
            | 
            | 
           792 | 
               }
  | 
        
        
            | 
            | 
           793 | 
              | 
        
        
            | 
            | 
           794 | 
               /**
  | 
        
        
            | 
            | 
           795 | 
                * Checks, that the specified element contains the specified text. When running Javascript tests it also considers that texts may be hidden.
  | 
        
        
            | 
            | 
           796 | 
                *
  | 
        
        
            | 
            | 
           797 | 
                * @Then /^I should see "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           798 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           799 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           800 | 
                * @param string $text
  | 
        
        
            | 
            | 
           801 | 
                * @param string $element Element we look in.
  | 
        
        
            | 
            | 
           802 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           803 | 
                */
  | 
        
        
            | 
            | 
           804 | 
               public function assert_element_contains_text($text, $element, $selectortype) {
  | 
        
        
            | 
            | 
           805 | 
              | 
        
        
            | 
            | 
           806 | 
                   // Getting the container where the text should be found.
  | 
        
        
            | 
            | 
           807 | 
                   $container = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           808 | 
              | 
        
        
            | 
            | 
           809 | 
                   // Looking for all the matching nodes without any other descendant matching the
  | 
        
        
            | 
            | 
           810 | 
                   // same xpath (we are using contains(., ....).
  | 
        
        
            | 
            | 
           811 | 
                   $xpathliteral = behat_context_helper::escape($text);
  | 
        
        
            | 
            | 
           812 | 
                   $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" .
  | 
        
        
            | 
            | 
           813 | 
                       "[count(descendant::*[contains(., $xpathliteral)]) = 0]";
  | 
        
        
            | 
            | 
           814 | 
              | 
        
        
            | 
            | 
           815 | 
                   // Wait until it finds the text inside the container, otherwise custom exception.
  | 
        
        
            | 
            | 
           816 | 
                   try {
  | 
        
        
            | 
            | 
           817 | 
                       $nodes = $this->find_all('xpath', $xpath, false, $container);
  | 
        
        
            | 
            | 
           818 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           819 | 
                       throw new ExpectationException('"' . $text . '" text was not found in the "' . $element . '" element', $this->getSession());
  | 
        
        
            | 
            | 
           820 | 
                   }
  | 
        
        
            | 
            | 
           821 | 
              | 
        
        
            | 
            | 
           822 | 
                   // If we are not running javascript we have enough with the
  | 
        
        
            | 
            | 
           823 | 
                   // element existing as we can't check if it is visible.
  | 
        
        
            | 
            | 
           824 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           825 | 
                       return;
  | 
        
        
            | 
            | 
           826 | 
                   }
  | 
        
        
            | 
            | 
           827 | 
              | 
        
        
            | 
            | 
           828 | 
                   // We also check the element visibility when running JS tests. Using microsleep as this
  | 
        
        
            | 
            | 
           829 | 
                   // is a repeated step and global performance is important.
  | 
        
        
            | 
            | 
           830 | 
                   $this->spin(
  | 
        
        
            | 
            | 
           831 | 
                       function($context, $args) {
  | 
        
        
            | 
            | 
           832 | 
              | 
        
        
            | 
            | 
           833 | 
                           foreach ($args['nodes'] as $node) {
  | 
        
        
            | 
            | 
           834 | 
                               if ($node->isVisible()) {
  | 
        
        
            | 
            | 
           835 | 
                                   return true;
  | 
        
        
            | 
            | 
           836 | 
                               }
  | 
        
        
            | 
            | 
           837 | 
                           }
  | 
        
        
            | 
            | 
           838 | 
              | 
        
        
            | 
            | 
           839 | 
                           throw new ExpectationException('"' . $args['text'] . '" text was found in the "' . $args['element'] . '" element but was not visible', $context->getSession());
  | 
        
        
            | 
            | 
           840 | 
                       },
  | 
        
        
            | 
            | 
           841 | 
                       array('nodes' => $nodes, 'text' => $text, 'element' => $element),
  | 
        
        
            | 
            | 
           842 | 
                       false,
  | 
        
        
            | 
            | 
           843 | 
                       false,
  | 
        
        
            | 
            | 
           844 | 
                       true
  | 
        
        
            | 
            | 
           845 | 
                   );
  | 
        
        
            | 
            | 
           846 | 
               }
  | 
        
        
            | 
            | 
           847 | 
              | 
        
        
            | 
            | 
           848 | 
               /**
  | 
        
        
            | 
            | 
           849 | 
                * Checks, that the specified element does not contain the specified text. When running Javascript tests it also considers that texts may be hidden.
  | 
        
        
            | 
            | 
           850 | 
                *
  | 
        
        
            | 
            | 
           851 | 
                * @Then /^I should not see "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           852 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           853 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           854 | 
                * @param string $text
  | 
        
        
            | 
            | 
           855 | 
                * @param string $element Element we look in.
  | 
        
        
            | 
            | 
           856 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           857 | 
                */
  | 
        
        
            | 
            | 
           858 | 
               public function assert_element_not_contains_text($text, $element, $selectortype) {
  | 
        
        
            | 
            | 
           859 | 
              | 
        
        
            | 
            | 
           860 | 
                   // Getting the container where the text should be found.
  | 
        
        
            | 
            | 
           861 | 
                   $container = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           862 | 
              | 
        
        
            | 
            | 
           863 | 
                   // Looking for all the matching nodes without any other descendant matching the
  | 
        
        
            | 
            | 
           864 | 
                   // same xpath (we are using contains(., ....).
  | 
        
        
            | 
            | 
           865 | 
                   $xpathliteral = behat_context_helper::escape($text);
  | 
        
        
            | 
            | 
           866 | 
                   $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" .
  | 
        
        
            | 
            | 
           867 | 
                       "[count(descendant::*[contains(., $xpathliteral)]) = 0]";
  | 
        
        
            | 
            | 
           868 | 
              | 
        
        
            | 
            | 
           869 | 
                   // We should wait a while to ensure that the page is not still loading elements.
  | 
        
        
            | 
            | 
           870 | 
                   // Giving preference to the reliability of the results rather than to the performance.
  | 
        
        
            | 
            | 
           871 | 
                   try {
  | 
        
        
            | 
            | 
           872 | 
                       $nodes = $this->find_all('xpath', $xpath, false, $container, self::get_reduced_timeout());
  | 
        
        
            | 
            | 
           873 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           874 | 
                       // All ok.
  | 
        
        
            | 
            | 
           875 | 
                       return;
  | 
        
        
            | 
            | 
           876 | 
                   }
  | 
        
        
            | 
            | 
           877 | 
              | 
        
        
            | 
            | 
           878 | 
                   // If we are not running javascript we have enough with the
  | 
        
        
            | 
            | 
           879 | 
                   // element not being found as we can't check if it is visible.
  | 
        
        
            | 
            | 
           880 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           881 | 
                       throw new ExpectationException('"' . $text . '" text was found in the "' . $element . '" element', $this->getSession());
  | 
        
        
            | 
            | 
           882 | 
                   }
  | 
        
        
            | 
            | 
           883 | 
              | 
        
        
            | 
            | 
           884 | 
                   // We need to ensure all the found nodes are hidden.
  | 
        
        
            | 
            | 
           885 | 
                   $this->spin(
  | 
        
        
            | 
            | 
           886 | 
                       function($context, $args) {
  | 
        
        
            | 
            | 
           887 | 
              | 
        
        
            | 
            | 
           888 | 
                           foreach ($args['nodes'] as $node) {
  | 
        
        
            | 
            | 
           889 | 
                               if ($node->isVisible()) {
  | 
        
        
            | 
            | 
           890 | 
                                   throw new ExpectationException('"' . $args['text'] . '" text was found in the "' . $args['element'] . '" element', $context->getSession());
  | 
        
        
            | 
            | 
           891 | 
                               }
  | 
        
        
            | 
            | 
           892 | 
                           }
  | 
        
        
            | 
            | 
           893 | 
              | 
        
        
            | 
            | 
           894 | 
                           // If all the found nodes are hidden we are happy.
  | 
        
        
            | 
            | 
           895 | 
                           return true;
  | 
        
        
            | 
            | 
           896 | 
                       },
  | 
        
        
            | 
            | 
           897 | 
                       array('nodes' => $nodes, 'text' => $text, 'element' => $element),
  | 
        
        
            | 
            | 
           898 | 
                       behat_base::get_reduced_timeout(),
  | 
        
        
            | 
            | 
           899 | 
                       false,
  | 
        
        
            | 
            | 
           900 | 
                       true
  | 
        
        
            | 
            | 
           901 | 
                   );
  | 
        
        
            | 
            | 
           902 | 
               }
  | 
        
        
            | 
            | 
           903 | 
              | 
        
        
            | 
            | 
           904 | 
               /**
  | 
        
        
            | 
            | 
           905 | 
                * Checks, that the first specified element appears before the second one.
  | 
        
        
            | 
            | 
           906 | 
                *
  | 
        
        
            | 
            | 
           907 | 
                * @Then :preelement :preselectortype should appear before :postelement :postselectortype
  | 
        
        
            | 
            | 
           908 | 
                * @Then :preelement :preselectortype should appear before :postelement :postselectortype in the :containerelement :containerselectortype
  | 
        
        
            | 
            | 
           909 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           910 | 
                * @param string $preelement The locator of the preceding element
  | 
        
        
            | 
            | 
           911 | 
                * @param string $preselectortype The selector type of the preceding element
  | 
        
        
            | 
            | 
           912 | 
                * @param string $postelement The locator of the latest element
  | 
        
        
            | 
            | 
           913 | 
                * @param string $postselectortype The selector type of the latest element
  | 
        
        
            | 
            | 
           914 | 
                * @param string $containerelement
  | 
        
        
            | 
            | 
           915 | 
                * @param string $containerselectortype
  | 
        
        
            | 
            | 
           916 | 
                */
  | 
        
        
            | 
            | 
           917 | 
               public function should_appear_before(
  | 
        
        
            | 
            | 
           918 | 
                   string $preelement,
  | 
        
        
            | 
            | 
           919 | 
                   string $preselectortype,
  | 
        
        
            | 
            | 
           920 | 
                   string $postelement,
  | 
        
        
            | 
            | 
           921 | 
                   string $postselectortype,
  | 
        
        
            | 
            | 
           922 | 
                   ?string $containerelement = null,
  | 
        
        
            | 
            | 
           923 | 
                   ?string $containerselectortype = null
  | 
        
        
            | 
            | 
           924 | 
               ) {
  | 
        
        
            | 
            | 
           925 | 
                   $msg = "'{$preelement}' '{$preselectortype}' does not appear before '{$postelement}' '{$postselectortype}'";
  | 
        
        
            | 
            | 
           926 | 
                   $this->check_element_order(
  | 
        
        
            | 
            | 
           927 | 
                       $containerelement,
  | 
        
        
            | 
            | 
           928 | 
                       $containerselectortype,
  | 
        
        
            | 
            | 
           929 | 
                       $preelement,
  | 
        
        
            | 
            | 
           930 | 
                       $preselectortype,
  | 
        
        
            | 
            | 
           931 | 
                       $postelement,
  | 
        
        
            | 
            | 
           932 | 
                       $postselectortype,
  | 
        
        
            | 
            | 
           933 | 
                       $msg
  | 
        
        
            | 
            | 
           934 | 
                   );
  | 
        
        
            | 
            | 
           935 | 
               }
  | 
        
        
            | 
            | 
           936 | 
              | 
        
        
            | 
            | 
           937 | 
               /**
  | 
        
        
            | 
            | 
           938 | 
                * Checks, that the first specified element appears after the second one.
  | 
        
        
            | 
            | 
           939 | 
                *
  | 
        
        
            | 
            | 
           940 | 
                * @Then :postelement :postselectortype should appear after :preelement :preselectortype
  | 
        
        
            | 
            | 
           941 | 
                * @Then :postelement :postselectortype should appear after :preelement :preselectortype in the :containerelement :containerselectortype
  | 
        
        
            | 
            | 
           942 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           943 | 
                * @param string $postelement The locator of the latest element
  | 
        
        
            | 
            | 
           944 | 
                * @param string $postselectortype The selector type of the latest element
  | 
        
        
            | 
            | 
           945 | 
                * @param string $preelement The locator of the preceding element
  | 
        
        
            | 
            | 
           946 | 
                * @param string $preselectortype The selector type of the preceding element
  | 
        
        
            | 
            | 
           947 | 
                * @param string $containerelement
  | 
        
        
            | 
            | 
           948 | 
                * @param string $containerselectortype
  | 
        
        
            | 
            | 
           949 | 
                */
  | 
        
        
            | 
            | 
           950 | 
               public function should_appear_after(
  | 
        
        
            | 
            | 
           951 | 
                   string $postelement,
  | 
        
        
            | 
            | 
           952 | 
                   string $postselectortype,
  | 
        
        
            | 
            | 
           953 | 
                   string $preelement,
  | 
        
        
            | 
            | 
           954 | 
                   string $preselectortype,
  | 
        
        
            | 
            | 
           955 | 
                   ?string $containerelement = null,
  | 
        
        
            | 
            | 
           956 | 
                   ?string $containerselectortype = null
  | 
        
        
            | 
            | 
           957 | 
               ) {
  | 
        
        
            | 
            | 
           958 | 
                   $msg = "'{$postelement}' '{$postselectortype}' does not appear after '{$preelement}' '{$preselectortype}'";
  | 
        
        
            | 
            | 
           959 | 
                   $this->check_element_order(
  | 
        
        
            | 
            | 
           960 | 
                       $containerelement,
  | 
        
        
            | 
            | 
           961 | 
                       $containerselectortype,
  | 
        
        
            | 
            | 
           962 | 
                       $preelement,
  | 
        
        
            | 
            | 
           963 | 
                       $preselectortype,
  | 
        
        
            | 
            | 
           964 | 
                       $postelement,
  | 
        
        
            | 
            | 
           965 | 
                       $postselectortype,
  | 
        
        
            | 
            | 
           966 | 
                       $msg
  | 
        
        
            | 
            | 
           967 | 
                   );
  | 
        
        
            | 
            | 
           968 | 
               }
  | 
        
        
            | 
            | 
           969 | 
              | 
        
        
            | 
            | 
           970 | 
               /**
  | 
        
        
            | 
            | 
           971 | 
                * Shared code to check whether an element is before or after another one.
  | 
        
        
            | 
            | 
           972 | 
                *
  | 
        
        
            | 
            | 
           973 | 
                * @param string $containerelement
  | 
        
        
            | 
            | 
           974 | 
                * @param string $containerselectortype
  | 
        
        
            | 
            | 
           975 | 
                * @param string $preelement The locator of the preceding element
  | 
        
        
            | 
            | 
           976 | 
                * @param string $preselectortype The locator of the preceding element
  | 
        
        
            | 
            | 
           977 | 
                * @param string $postelement The locator of the following element
  | 
        
        
            | 
            | 
           978 | 
                * @param string $postselectortype The selector type of the following element
  | 
        
        
            | 
            | 
           979 | 
                * @param string $msg Message to output if this fails
  | 
        
        
            | 
            | 
           980 | 
                */
  | 
        
        
            | 
            | 
           981 | 
               protected function check_element_order(
  | 
        
        
            | 
            | 
           982 | 
                   ?string $containerelement,
  | 
        
        
            | 
            | 
           983 | 
                   ?string $containerselectortype,
  | 
        
        
            | 
            | 
           984 | 
                   string $preelement,
  | 
        
        
            | 
            | 
           985 | 
                   string $preselectortype,
  | 
        
        
            | 
            | 
           986 | 
                   string $postelement,
  | 
        
        
            | 
            | 
           987 | 
                   string $postselectortype,
  | 
        
        
            | 
            | 
           988 | 
                   string $msg
  | 
        
        
            | 
            | 
           989 | 
               ) {
  | 
        
        
            | 
            | 
           990 | 
                   $containernode = false;
  | 
        
        
            | 
            | 
           991 | 
                   if ($containerselectortype && $containerelement) {
  | 
        
        
            | 
            | 
           992 | 
                       // Get the container node.
  | 
        
        
            | 
            | 
           993 | 
                       $containernode = $this->get_selected_node($containerselectortype, $containerelement);
  | 
        
        
            | 
            | 
           994 | 
                       $msg .= " in the '{$containerelement}' '{$containerselectortype}'";
  | 
        
        
            | 
            | 
           995 | 
                   }
  | 
        
        
            | 
            | 
           996 | 
              | 
        
        
           | 1441 | 
           ariadna | 
           997 | 
                   [$preselector, $prelocator] = $this->transform_selector($preselectortype, $preelement);
  | 
        
        
            | 
            | 
           998 | 
                   [$postselector, $postlocator] = $this->transform_selector($postselectortype, $postelement);
  | 
        
        
           | 1 | 
           efrain | 
           999 | 
              | 
        
        
           | 1441 | 
           ariadna | 
           1000 | 
                   $prexpath = $this->prepare_xpath_for_javascript(
  | 
        
        
            | 
            | 
           1001 | 
                       $this->find($preselector, $prelocator, false, $containernode)->getXpath()
  | 
        
        
            | 
            | 
           1002 | 
                   );
  | 
        
        
            | 
            | 
           1003 | 
                   $postxpath = $this->prepare_xpath_for_javascript(
  | 
        
        
            | 
            | 
           1004 | 
                       $this->find($postselector, $postlocator, false, $containernode)->getXpath()
  | 
        
        
            | 
            | 
           1005 | 
                   );
  | 
        
        
           | 1 | 
           efrain | 
           1006 | 
              | 
        
        
            | 
            | 
           1007 | 
                   if ($this->running_javascript()) {
  | 
        
        
            | 
            | 
           1008 | 
                       // The xpath to do this was running really slowly on certain Chrome versions so we are using
  | 
        
        
            | 
            | 
           1009 | 
                       // this DOM method instead.
  | 
        
        
            | 
            | 
           1010 | 
                       $js = <<<EOF
  | 
        
        
            | 
            | 
           1011 | 
           (function() {
  | 
        
        
            | 
            | 
           1012 | 
               var a = document.evaluate("{$prexpath}", document, null, XPathResult.ANY_TYPE, null).iterateNext();
  | 
        
        
            | 
            | 
           1013 | 
               var b = document.evaluate("{$postxpath}", document, null, XPathResult.ANY_TYPE, null).iterateNext();
  | 
        
        
            | 
            | 
           1014 | 
               return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING;
  | 
        
        
            | 
            | 
           1015 | 
           })()
  | 
        
        
            | 
            | 
           1016 | 
           EOF;
  | 
        
        
            | 
            | 
           1017 | 
                       $ok = $this->evaluate_script($js);
  | 
        
        
            | 
            | 
           1018 | 
                   } else {
  | 
        
        
            | 
            | 
           1019 | 
              | 
        
        
            | 
            | 
           1020 | 
                       // Using following xpath axe to find it.
  | 
        
        
            | 
            | 
           1021 | 
                       $xpath = "{$prexpath}/following::*[contains(., {$postxpath})]";
  | 
        
        
            | 
            | 
           1022 | 
                       $ok = $this->getSession()->getDriver()->find($xpath);
  | 
        
        
            | 
            | 
           1023 | 
                   }
  | 
        
        
            | 
            | 
           1024 | 
              | 
        
        
            | 
            | 
           1025 | 
                   if (!$ok) {
  | 
        
        
            | 
            | 
           1026 | 
                       throw new ExpectationException($msg, $this->getSession());
  | 
        
        
            | 
            | 
           1027 | 
                   }
  | 
        
        
            | 
            | 
           1028 | 
               }
  | 
        
        
            | 
            | 
           1029 | 
              | 
        
        
            | 
            | 
           1030 | 
               /**
  | 
        
        
            | 
            | 
           1031 | 
                * Checks, that element of specified type is disabled.
  | 
        
        
            | 
            | 
           1032 | 
                *
  | 
        
        
            | 
            | 
           1033 | 
                * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be disabled$/
  | 
        
        
            | 
            | 
           1034 | 
                * @throws ExpectationException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           1035 | 
                * @param string $element Element we look in
  | 
        
        
            | 
            | 
           1036 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           1037 | 
                */
  | 
        
        
            | 
            | 
           1038 | 
               public function the_element_should_be_disabled($element, $selectortype) {
  | 
        
        
            | 
            | 
           1039 | 
                   $this->the_attribute_of_should_be_set("disabled", $element, $selectortype, false);
  | 
        
        
            | 
            | 
           1040 | 
               }
  | 
        
        
            | 
            | 
           1041 | 
              | 
        
        
            | 
            | 
           1042 | 
               /**
  | 
        
        
            | 
            | 
           1043 | 
                * Checks, that element of specified type is enabled.
  | 
        
        
            | 
            | 
           1044 | 
                *
  | 
        
        
            | 
            | 
           1045 | 
                * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be enabled$/
  | 
        
        
            | 
            | 
           1046 | 
                * @throws ExpectationException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           1047 | 
                * @param string $element Element we look on
  | 
        
        
            | 
            | 
           1048 | 
                * @param string $selectortype The type of where we look
  | 
        
        
            | 
            | 
           1049 | 
                */
  | 
        
        
            | 
            | 
           1050 | 
               public function the_element_should_be_enabled($element, $selectortype) {
  | 
        
        
            | 
            | 
           1051 | 
                   $this->the_attribute_of_should_be_set("disabled", $element, $selectortype, true);
  | 
        
        
            | 
            | 
           1052 | 
               }
  | 
        
        
            | 
            | 
           1053 | 
              | 
        
        
            | 
            | 
           1054 | 
               /**
  | 
        
        
            | 
            | 
           1055 | 
                * Checks the provided element and selector type are readonly on the current page.
  | 
        
        
            | 
            | 
           1056 | 
                *
  | 
        
        
            | 
            | 
           1057 | 
                * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be readonly$/
  | 
        
        
            | 
            | 
           1058 | 
                * @throws ExpectationException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           1059 | 
                * @param string $element Element we look in
  | 
        
        
            | 
            | 
           1060 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           1061 | 
                */
  | 
        
        
            | 
            | 
           1062 | 
               public function the_element_should_be_readonly($element, $selectortype) {
  | 
        
        
            | 
            | 
           1063 | 
                   $this->the_attribute_of_should_be_set("readonly", $element, $selectortype, false);
  | 
        
        
            | 
            | 
           1064 | 
               }
  | 
        
        
            | 
            | 
           1065 | 
              | 
        
        
            | 
            | 
           1066 | 
               /**
  | 
        
        
            | 
            | 
           1067 | 
                * Checks the provided element and selector type are not readonly on the current page.
  | 
        
        
            | 
            | 
           1068 | 
                *
  | 
        
        
            | 
            | 
           1069 | 
                * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not be readonly$/
  | 
        
        
            | 
            | 
           1070 | 
                * @throws ExpectationException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           1071 | 
                * @param string $element Element we look in
  | 
        
        
            | 
            | 
           1072 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           1073 | 
                */
  | 
        
        
            | 
            | 
           1074 | 
               public function the_element_should_not_be_readonly($element, $selectortype) {
  | 
        
        
            | 
            | 
           1075 | 
                   $this->the_attribute_of_should_be_set("readonly", $element, $selectortype, true);
  | 
        
        
            | 
            | 
           1076 | 
               }
  | 
        
        
            | 
            | 
           1077 | 
              | 
        
        
            | 
            | 
           1078 | 
               /**
  | 
        
        
            | 
            | 
           1079 | 
                * Checks the provided element and selector type exists in the current page.
  | 
        
        
            | 
            | 
           1080 | 
                *
  | 
        
        
            | 
            | 
           1081 | 
                * This step is for advanced users, use it if you don't find anything else suitable for what you need.
  | 
        
        
            | 
            | 
           1082 | 
                *
  | 
        
        
            | 
            | 
           1083 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should exist$/
  | 
        
        
            | 
            | 
           1084 | 
                * @throws ElementNotFoundException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           1085 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1086 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1087 | 
                */
  | 
        
        
            | 
            | 
           1088 | 
               public function should_exist($element, $selectortype) {
  | 
        
        
            | 
            | 
           1089 | 
                   // Will throw an ElementNotFoundException if it does not exist.
  | 
        
        
            | 
            | 
           1090 | 
                   $this->find($selectortype, $element);
  | 
        
        
            | 
            | 
           1091 | 
               }
  | 
        
        
            | 
            | 
           1092 | 
              | 
        
        
            | 
            | 
           1093 | 
               /**
  | 
        
        
            | 
            | 
           1094 | 
                * Checks that the provided element and selector type not exists in the current page.
  | 
        
        
            | 
            | 
           1095 | 
                *
  | 
        
        
            | 
            | 
           1096 | 
                * This step is for advanced users, use it if you don't find anything else suitable for what you need.
  | 
        
        
            | 
            | 
           1097 | 
                *
  | 
        
        
            | 
            | 
           1098 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not exist$/
  | 
        
        
            | 
            | 
           1099 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1100 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1101 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1102 | 
                */
  | 
        
        
            | 
            | 
           1103 | 
               public function should_not_exist($element, $selectortype) {
  | 
        
        
            | 
            | 
           1104 | 
                   // Will throw an ElementNotFoundException if it does not exist, but, actually it should not exist, so we try &
  | 
        
        
            | 
            | 
           1105 | 
                   // catch it.
  | 
        
        
            | 
            | 
           1106 | 
                   try {
  | 
        
        
            | 
            | 
           1107 | 
                       // The exception does not really matter as we will catch it and will never "explode".
  | 
        
        
            | 
            | 
           1108 | 
                       $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $element);
  | 
        
        
            | 
            | 
           1109 | 
              | 
        
        
            | 
            | 
           1110 | 
                       // Using the spin method as we want a reduced timeout but there is no need for a 0.1 seconds interval
  | 
        
        
            | 
            | 
           1111 | 
                       // because in the optimistic case we will timeout.
  | 
        
        
            | 
            | 
           1112 | 
                       // If all goes good it will throw an ElementNotFoundExceptionn that we will catch.
  | 
        
        
            | 
            | 
           1113 | 
                       $this->find($selectortype, $element, $exception, false, behat_base::get_reduced_timeout());
  | 
        
        
            | 
            | 
           1114 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           1115 | 
                       // We expect the element to not be found.
  | 
        
        
            | 
            | 
           1116 | 
                       return;
  | 
        
        
            | 
            | 
           1117 | 
                   }
  | 
        
        
            | 
            | 
           1118 | 
              | 
        
        
            | 
            | 
           1119 | 
                   // The element was found and should not have been. Throw an exception.
  | 
        
        
            | 
            | 
           1120 | 
                   throw new ExpectationException("The '{$element}' '{$selectortype}' exists in the current page", $this->getSession());
  | 
        
        
            | 
            | 
           1121 | 
               }
  | 
        
        
            | 
            | 
           1122 | 
              | 
        
        
            | 
            | 
           1123 | 
               /**
  | 
        
        
            | 
            | 
           1124 | 
                * Ensure that edit mode is (not) available on the current page.
  | 
        
        
            | 
            | 
           1125 | 
                *
  | 
        
        
            | 
            | 
           1126 | 
                * @Then edit mode should be available on the current page
  | 
        
        
            | 
            | 
           1127 | 
                * @Then edit mode should :not be available on the current page
  | 
        
        
            | 
            | 
           1128 | 
                * @param bool $not
  | 
        
        
            | 
            | 
           1129 | 
                */
  | 
        
        
            | 
            | 
           1130 | 
               public function edit_mode_should_be_available(bool $not = false): void {
  | 
        
        
            | 
            | 
           1131 | 
                   $isavailable = $this->is_edit_mode_available();
  | 
        
        
            | 
            | 
           1132 | 
                   $shouldbeavailable = empty($not);
  | 
        
        
            | 
            | 
           1133 | 
              | 
        
        
            | 
            | 
           1134 | 
                   if ($isavailable && !$shouldbeavailable) {
  | 
        
        
            | 
            | 
           1135 | 
                       throw new ExpectationException("Edit mode is available and should not be", $this->getSession());
  | 
        
        
            | 
            | 
           1136 | 
                   } else if ($shouldbeavailable && !$isavailable) {
  | 
        
        
            | 
            | 
           1137 | 
                       throw new ExpectationException("Edit mode is not available and should be", $this->getSession());
  | 
        
        
            | 
            | 
           1138 | 
                   }
  | 
        
        
            | 
            | 
           1139 | 
               }
  | 
        
        
            | 
            | 
           1140 | 
              | 
        
        
            | 
            | 
           1141 | 
               /**
  | 
        
        
            | 
            | 
           1142 | 
                * Check whether edit mode is available on the current page.
  | 
        
        
            | 
            | 
           1143 | 
                *
  | 
        
        
            | 
            | 
           1144 | 
                * @return bool
  | 
        
        
            | 
            | 
           1145 | 
                */
  | 
        
        
            | 
            | 
           1146 | 
               public function is_edit_mode_available(): bool {
  | 
        
        
            | 
            | 
           1147 | 
                   // If the course is already in editing mode then it will have the class 'editing' on the body.
  | 
        
        
            | 
            | 
           1148 | 
                   // This is a 'cheap' way of telling if the course is in editing mode and therefore if edit mode is available.
  | 
        
        
            | 
            | 
           1149 | 
                   $body = $this->find('css', 'body');
  | 
        
        
            | 
            | 
           1150 | 
                   if ($body->hasClass('editing')) {
  | 
        
        
            | 
            | 
           1151 | 
                       return true;
  | 
        
        
            | 
            | 
           1152 | 
                   }
  | 
        
        
            | 
            | 
           1153 | 
              | 
        
        
            | 
            | 
           1154 | 
                   try {
  | 
        
        
            | 
            | 
           1155 | 
                       $this->find('field', get_string('editmode'), false, false, 0);
  | 
        
        
            | 
            | 
           1156 | 
                       return true;
  | 
        
        
            | 
            | 
           1157 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           1158 | 
                       return false;
  | 
        
        
            | 
            | 
           1159 | 
                   }
  | 
        
        
            | 
            | 
           1160 | 
               }
  | 
        
        
            | 
            | 
           1161 | 
              | 
        
        
            | 
            | 
           1162 | 
               /**
  | 
        
        
            | 
            | 
           1163 | 
                * This step triggers cron like a user would do going to admin/cron.php.
  | 
        
        
            | 
            | 
           1164 | 
                *
  | 
        
        
            | 
            | 
           1165 | 
                * @Given /^I trigger cron$/
  | 
        
        
            | 
            | 
           1166 | 
                */
  | 
        
        
            | 
            | 
           1167 | 
               public function i_trigger_cron() {
  | 
        
        
           | 1441 | 
           ariadna | 
           1168 | 
                   $this->execute([self::class, 'i_visit'], ['/admin/cron.php']);
  | 
        
        
           | 1 | 
           efrain | 
           1169 | 
               }
  | 
        
        
            | 
            | 
           1170 | 
              | 
        
        
            | 
            | 
           1171 | 
               /**
  | 
        
        
            | 
            | 
           1172 | 
                * Runs a scheduled task immediately, given full class name.
  | 
        
        
            | 
            | 
           1173 | 
                *
  | 
        
        
            | 
            | 
           1174 | 
                * This is faster and more reliable than running cron (running cron won't
  | 
        
        
            | 
            | 
           1175 | 
                * work more than once in the same test, for instance). However it is
  | 
        
        
            | 
            | 
           1176 | 
                * a little less 'realistic'.
  | 
        
        
            | 
            | 
           1177 | 
                *
  | 
        
        
            | 
            | 
           1178 | 
                * While the task is running, we suppress mtrace output because it makes
  | 
        
        
            | 
            | 
           1179 | 
                * the Behat result look ugly.
  | 
        
        
            | 
            | 
           1180 | 
                *
  | 
        
        
            | 
            | 
           1181 | 
                * Note: Most of the code relating to running a task is based on
  | 
        
        
            | 
            | 
           1182 | 
                * admin/cli/scheduled_task.php.
  | 
        
        
            | 
            | 
           1183 | 
                *
  | 
        
        
            | 
            | 
           1184 | 
                * @Given /^I run the scheduled task "(?P<task_name>[^"]+)"$/
  | 
        
        
            | 
            | 
           1185 | 
                * @param string $taskname Name of task e.g. 'mod_whatever\task\do_something'
  | 
        
        
            | 
            | 
           1186 | 
                */
  | 
        
        
            | 
            | 
           1187 | 
               public function i_run_the_scheduled_task($taskname) {
  | 
        
        
            | 
            | 
           1188 | 
                   $task = \core\task\manager::get_scheduled_task($taskname);
  | 
        
        
            | 
            | 
           1189 | 
                   if (!$task) {
  | 
        
        
            | 
            | 
           1190 | 
                       throw new DriverException('The "' . $taskname . '" scheduled task does not exist');
  | 
        
        
            | 
            | 
           1191 | 
                   }
  | 
        
        
            | 
            | 
           1192 | 
              | 
        
        
            | 
            | 
           1193 | 
                   // Do setup for cron task.
  | 
        
        
            | 
            | 
           1194 | 
                   raise_memory_limit(MEMORY_EXTRA);
  | 
        
        
            | 
            | 
           1195 | 
                   \core\cron::setup_user();
  | 
        
        
            | 
            | 
           1196 | 
              | 
        
        
            | 
            | 
           1197 | 
                   // Get lock.
  | 
        
        
            | 
            | 
           1198 | 
                   $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
  | 
        
        
            | 
            | 
           1199 | 
                   if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10)) {
  | 
        
        
            | 
            | 
           1200 | 
                       throw new DriverException('Unable to obtain core_cron lock for scheduled task');
  | 
        
        
            | 
            | 
           1201 | 
                   }
  | 
        
        
            | 
            | 
           1202 | 
                   if (!$lock = $cronlockfactory->get_lock('\\' . get_class($task), 10)) {
  | 
        
        
            | 
            | 
           1203 | 
                       $cronlock->release();
  | 
        
        
            | 
            | 
           1204 | 
                       throw new DriverException('Unable to obtain task lock for scheduled task');
  | 
        
        
            | 
            | 
           1205 | 
                   }
  | 
        
        
            | 
            | 
           1206 | 
                   $task->set_lock($lock);
  | 
        
        
            | 
            | 
           1207 | 
                   $cronlock->release();
  | 
        
        
            | 
            | 
           1208 | 
              | 
        
        
            | 
            | 
           1209 | 
                   try {
  | 
        
        
            | 
            | 
           1210 | 
                       // Prepare the renderer.
  | 
        
        
            | 
            | 
           1211 | 
                       \core\cron::prepare_core_renderer();
  | 
        
        
            | 
            | 
           1212 | 
              | 
        
        
            | 
            | 
           1213 | 
                       // Discard task output as not appropriate for Behat output!
  | 
        
        
            | 
            | 
           1214 | 
                       ob_start();
  | 
        
        
            | 
            | 
           1215 | 
                       $task->execute();
  | 
        
        
            | 
            | 
           1216 | 
                       ob_end_clean();
  | 
        
        
            | 
            | 
           1217 | 
              | 
        
        
            | 
            | 
           1218 | 
                       // Restore the previous renderer.
  | 
        
        
            | 
            | 
           1219 | 
                       \core\cron::prepare_core_renderer(true);
  | 
        
        
            | 
            | 
           1220 | 
              | 
        
        
            | 
            | 
           1221 | 
                       // Mark task complete.
  | 
        
        
            | 
            | 
           1222 | 
                       \core\task\manager::scheduled_task_complete($task);
  | 
        
        
            | 
            | 
           1223 | 
                   } catch (Exception $e) {
  | 
        
        
            | 
            | 
           1224 | 
                       // Restore the previous renderer.
  | 
        
        
            | 
            | 
           1225 | 
                       \core\cron::prepare_core_renderer(true);
  | 
        
        
            | 
            | 
           1226 | 
              | 
        
        
            | 
            | 
           1227 | 
                       // Mark task failed and throw exception.
  | 
        
        
            | 
            | 
           1228 | 
                       \core\task\manager::scheduled_task_failed($task);
  | 
        
        
            | 
            | 
           1229 | 
              | 
        
        
            | 
            | 
           1230 | 
                       throw new DriverException('The "' . $taskname . '" scheduled task failed', 0, $e);
  | 
        
        
            | 
            | 
           1231 | 
                   }
  | 
        
        
            | 
            | 
           1232 | 
               }
  | 
        
        
            | 
            | 
           1233 | 
              | 
        
        
            | 
            | 
           1234 | 
               /**
  | 
        
        
            | 
            | 
           1235 | 
                * Runs all ad-hoc tasks in the queue.
  | 
        
        
            | 
            | 
           1236 | 
                *
  | 
        
        
            | 
            | 
           1237 | 
                * This is faster and more reliable than running cron (running cron won't
  | 
        
        
            | 
            | 
           1238 | 
                * work more than once in the same test, for instance). However it is
  | 
        
        
            | 
            | 
           1239 | 
                * a little less 'realistic'.
  | 
        
        
            | 
            | 
           1240 | 
                *
  | 
        
        
            | 
            | 
           1241 | 
                * While the task is running, we suppress mtrace output because it makes
  | 
        
        
            | 
            | 
           1242 | 
                * the Behat result look ugly.
  | 
        
        
            | 
            | 
           1243 | 
                *
  | 
        
        
            | 
            | 
           1244 | 
                * @Given /^I run all adhoc tasks$/
  | 
        
        
            | 
            | 
           1245 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           1246 | 
                */
  | 
        
        
            | 
            | 
           1247 | 
               public function i_run_all_adhoc_tasks() {
  | 
        
        
            | 
            | 
           1248 | 
                   global $DB;
  | 
        
        
            | 
            | 
           1249 | 
              | 
        
        
            | 
            | 
           1250 | 
                   // Do setup for cron task.
  | 
        
        
            | 
            | 
           1251 | 
                   \core\cron::setup_user();
  | 
        
        
            | 
            | 
           1252 | 
              | 
        
        
            | 
            | 
           1253 | 
                   // Discard task output as not appropriate for Behat output!
  | 
        
        
            | 
            | 
           1254 | 
                   ob_start();
  | 
        
        
            | 
            | 
           1255 | 
              | 
        
        
            | 
            | 
           1256 | 
                   // Run all tasks which have a scheduled runtime of before now.
  | 
        
        
            | 
            | 
           1257 | 
                   $timenow = time();
  | 
        
        
            | 
            | 
           1258 | 
              | 
        
        
            | 
            | 
           1259 | 
                   while (!\core\task\manager::static_caches_cleared_since($timenow) &&
  | 
        
        
            | 
            | 
           1260 | 
                           $task = \core\task\manager::get_next_adhoc_task($timenow)) {
  | 
        
        
            | 
            | 
           1261 | 
                       // Clean the output buffer between tasks.
  | 
        
        
            | 
            | 
           1262 | 
                       ob_clean();
  | 
        
        
            | 
            | 
           1263 | 
              | 
        
        
            | 
            | 
           1264 | 
                       // Run the task.
  | 
        
        
            | 
            | 
           1265 | 
                       \core\cron::run_inner_adhoc_task($task);
  | 
        
        
            | 
            | 
           1266 | 
              | 
        
        
            | 
            | 
           1267 | 
                       // Check whether the task record still exists.
  | 
        
        
            | 
            | 
           1268 | 
                       // If a task was successful it will be removed.
  | 
        
        
            | 
            | 
           1269 | 
                       // If it failed then it will still exist.
  | 
        
        
            | 
            | 
           1270 | 
                       if ($DB->record_exists('task_adhoc', ['id' => $task->get_id()])) {
  | 
        
        
            | 
            | 
           1271 | 
                           // End ouptut buffering and flush the current buffer.
  | 
        
        
            | 
            | 
           1272 | 
                           // This should be from just the current task.
  | 
        
        
            | 
            | 
           1273 | 
                           ob_end_flush();
  | 
        
        
            | 
            | 
           1274 | 
              | 
        
        
            | 
            | 
           1275 | 
                           throw new DriverException('An adhoc task failed', 0);
  | 
        
        
            | 
            | 
           1276 | 
                       }
  | 
        
        
            | 
            | 
           1277 | 
                   }
  | 
        
        
            | 
            | 
           1278 | 
                   ob_end_clean();
  | 
        
        
            | 
            | 
           1279 | 
               }
  | 
        
        
            | 
            | 
           1280 | 
              | 
        
        
            | 
            | 
           1281 | 
               /**
  | 
        
        
            | 
            | 
           1282 | 
                * Checks that an element and selector type exists in another element and selector type on the current page.
  | 
        
        
            | 
            | 
           1283 | 
                *
  | 
        
        
            | 
            | 
           1284 | 
                * This step is for advanced users, use it if you don't find anything else suitable for what you need.
  | 
        
        
            | 
            | 
           1285 | 
                *
  | 
        
        
            | 
            | 
           1286 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should exist in the "(?P<element2_string>(?:[^"]|\\")*)" "(?P<selector2_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           1287 | 
                * @throws ElementNotFoundException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           1288 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1289 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1290 | 
                * @param NodeElement|string $containerelement The locator of the container selector
  | 
        
        
            | 
            | 
           1291 | 
                * @param string $containerselectortype The container selector type
  | 
        
        
            | 
            | 
           1292 | 
                */
  | 
        
        
            | 
            | 
           1293 | 
               public function should_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) {
  | 
        
        
            | 
            | 
           1294 | 
                   // Will throw an ElementNotFoundException if it does not exist.
  | 
        
        
            | 
            | 
           1295 | 
                   $this->get_node_in_container($selectortype, $element, $containerselectortype, $containerelement);
  | 
        
        
            | 
            | 
           1296 | 
               }
  | 
        
        
            | 
            | 
           1297 | 
              | 
        
        
            | 
            | 
           1298 | 
               /**
  | 
        
        
            | 
            | 
           1299 | 
                * Checks that an element and selector type does not exist in another element and selector type on the current page.
  | 
        
        
            | 
            | 
           1300 | 
                *
  | 
        
        
            | 
            | 
           1301 | 
                * This step is for advanced users, use it if you don't find anything else suitable for what you need.
  | 
        
        
            | 
            | 
           1302 | 
                *
  | 
        
        
            | 
            | 
           1303 | 
                * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not exist in the "(?P<element2_string>(?:[^"]|\\")*)" "(?P<selector2_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           1304 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1305 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1306 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1307 | 
                * @param NodeElement|string $containerelement The locator of the container selector
  | 
        
        
            | 
            | 
           1308 | 
                * @param string $containerselectortype The container selector type
  | 
        
        
            | 
            | 
           1309 | 
                */
  | 
        
        
            | 
            | 
           1310 | 
               public function should_not_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) {
  | 
        
        
            | 
            | 
           1311 | 
                   // Get the container node.
  | 
        
        
            | 
            | 
           1312 | 
                   $containernode = $this->find($containerselectortype, $containerelement);
  | 
        
        
            | 
            | 
           1313 | 
              | 
        
        
            | 
            | 
           1314 | 
                   // Will throw an ElementNotFoundException if it does not exist, but, actually it should not exist, so we try &
  | 
        
        
            | 
            | 
           1315 | 
                   // catch it.
  | 
        
        
            | 
            | 
           1316 | 
                   try {
  | 
        
        
            | 
            | 
           1317 | 
                       // Looks for the requested node inside the container node.
  | 
        
        
            | 
            | 
           1318 | 
                       $this->find($selectortype, $element, false, $containernode, behat_base::get_reduced_timeout());
  | 
        
        
            | 
            | 
           1319 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           1320 | 
                       // We expect the element to not be found.
  | 
        
        
            | 
            | 
           1321 | 
                       return;
  | 
        
        
            | 
            | 
           1322 | 
                   }
  | 
        
        
            | 
            | 
           1323 | 
              | 
        
        
            | 
            | 
           1324 | 
                   // The element was found and should not have been. Throw an exception.
  | 
        
        
            | 
            | 
           1325 | 
                   $elementdescription = $this->get_selector_description($selectortype, $element);
  | 
        
        
            | 
            | 
           1326 | 
                   $containerdescription = $this->get_selector_description($containerselectortype, $containerelement);
  | 
        
        
            | 
            | 
           1327 | 
                   throw new ExpectationException(
  | 
        
        
            | 
            | 
           1328 | 
                       "The {$elementdescription} exists in the {$containerdescription}",
  | 
        
        
            | 
            | 
           1329 | 
                       $this->getSession()
  | 
        
        
            | 
            | 
           1330 | 
                   );
  | 
        
        
            | 
            | 
           1331 | 
               }
  | 
        
        
            | 
            | 
           1332 | 
              | 
        
        
            | 
            | 
           1333 | 
               /**
  | 
        
        
            | 
            | 
           1334 | 
                * Change browser window size
  | 
        
        
            | 
            | 
           1335 | 
                *
  | 
        
        
            | 
            | 
           1336 | 
                * Allowed sizes:
  | 
        
        
            | 
            | 
           1337 | 
                * - mobile: 425x750
  | 
        
        
            | 
            | 
           1338 | 
                * - tablet: 768x1024
  | 
        
        
            | 
            | 
           1339 | 
                * - small: 1024x768
  | 
        
        
            | 
            | 
           1340 | 
                * - medium: 1366x768
  | 
        
        
            | 
            | 
           1341 | 
                * - large: 2560x1600
  | 
        
        
            | 
            | 
           1342 | 
                * - custom: widthxheight
  | 
        
        
            | 
            | 
           1343 | 
                *
  | 
        
        
            | 
            | 
           1344 | 
                * Example: I change window size to "small" or I change window size to "1024x768"
  | 
        
        
            | 
            | 
           1345 | 
                * or I change viewport size to "800x600". The viewport option is useful to guarantee that the
  | 
        
        
            | 
            | 
           1346 | 
                * browser window has same viewport size even when you run Behat on multiple operating systems.
  | 
        
        
            | 
            | 
           1347 | 
                *
  | 
        
        
            | 
            | 
           1348 | 
                * @throws ExpectationException
  | 
        
        
           | 1441 | 
           ariadna | 
           1349 | 
                * @Then /^I change (window|viewport) size to "(mobile|tablet|small|medium|large|\d+x\d+)"( without runtime scaling)?$/
  | 
        
        
            | 
            | 
           1350 | 
                * @Then /^I change the (window|viewport) size to "(mobile|tablet|small|medium|large|\d+x\d+)"( without runtime scaling)?$/
  | 
        
        
            | 
            | 
           1351 | 
                * @param string $windowviewport Whether this is a window or viewport size hcange
  | 
        
        
           | 1 | 
           efrain | 
           1352 | 
                * @param string $windowsize size of the window (mobile|tablet|small|medium|large|wxh).
  | 
        
        
           | 1441 | 
           ariadna | 
           1353 | 
                * @param null|string $scale whether to lock runtime scaling (string) or to allow it (null)
  | 
        
        
           | 1 | 
           efrain | 
           1354 | 
                */
  | 
        
        
           | 1441 | 
           ariadna | 
           1355 | 
               public function i_change_window_size_to(
  | 
        
        
            | 
            | 
           1356 | 
                   $windowviewport,
  | 
        
        
            | 
            | 
           1357 | 
                   $windowsize,
  | 
        
        
            | 
            | 
           1358 | 
                   ?string $scale = null,
  | 
        
        
            | 
            | 
           1359 | 
               ): void {
  | 
        
        
            | 
            | 
           1360 | 
                   $this->resize_window(
  | 
        
        
            | 
            | 
           1361 | 
                       $windowsize,
  | 
        
        
            | 
            | 
           1362 | 
                       $windowviewport === 'viewport',
  | 
        
        
            | 
            | 
           1363 | 
                       $scale === null,
  | 
        
        
            | 
            | 
           1364 | 
                   );
  | 
        
        
           | 1 | 
           efrain | 
           1365 | 
               }
  | 
        
        
            | 
            | 
           1366 | 
              | 
        
        
            | 
            | 
           1367 | 
               /**
  | 
        
        
            | 
            | 
           1368 | 
                * Checks whether there the specified attribute is set or not.
  | 
        
        
            | 
            | 
           1369 | 
                *
  | 
        
        
            | 
            | 
           1370 | 
                * @Then the :attribute attribute of :element :selectortype should be set
  | 
        
        
            | 
            | 
           1371 | 
                * @Then the :attribute attribute of :element :selectortype should :not be set
  | 
        
        
            | 
            | 
           1372 | 
                *
  | 
        
        
            | 
            | 
           1373 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1374 | 
                * @param string $attribute Name of attribute
  | 
        
        
            | 
            | 
           1375 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1376 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1377 | 
                * @param string $not
  | 
        
        
            | 
            | 
           1378 | 
                */
  | 
        
        
            | 
            | 
           1379 | 
               public function the_attribute_of_should_be_set($attribute, $element, $selectortype, $not = null) {
  | 
        
        
            | 
            | 
           1380 | 
                   // Get the container node (exception if it doesn't exist).
  | 
        
        
            | 
            | 
           1381 | 
                   $containernode = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           1382 | 
                   $hasattribute = $containernode->hasAttribute($attribute);
  | 
        
        
            | 
            | 
           1383 | 
              | 
        
        
            | 
            | 
           1384 | 
                   if ($not && $hasattribute) {
  | 
        
        
            | 
            | 
           1385 | 
                       $value = $containernode->getAttribute($attribute);
  | 
        
        
            | 
            | 
           1386 | 
                       // Should not be set but is.
  | 
        
        
            | 
            | 
           1387 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           1388 | 
                           "The attribute \"{$attribute}\" should not be set but has a value of '{$value}'",
  | 
        
        
            | 
            | 
           1389 | 
                           $this->getSession()
  | 
        
        
            | 
            | 
           1390 | 
                       );
  | 
        
        
            | 
            | 
           1391 | 
                   } else if (!$not && !$hasattribute) {
  | 
        
        
            | 
            | 
           1392 | 
                       // Should be set but is not.
  | 
        
        
            | 
            | 
           1393 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           1394 | 
                           "The attribute \"{$attribute}\" should be set but is not",
  | 
        
        
            | 
            | 
           1395 | 
                           $this->getSession()
  | 
        
        
            | 
            | 
           1396 | 
                       );
  | 
        
        
            | 
            | 
           1397 | 
                   }
  | 
        
        
            | 
            | 
           1398 | 
               }
  | 
        
        
            | 
            | 
           1399 | 
              | 
        
        
            | 
            | 
           1400 | 
               /**
  | 
        
        
            | 
            | 
           1401 | 
                * Checks whether there is an attribute on the given element that contains the specified text.
  | 
        
        
            | 
            | 
           1402 | 
                *
  | 
        
        
            | 
            | 
           1403 | 
                * @Then /^the "(?P<attribute_string>[^"]*)" attribute of "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should contain "(?P<text_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           1404 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1405 | 
                * @param string $attribute Name of attribute
  | 
        
        
            | 
            | 
           1406 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1407 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1408 | 
                * @param string $text Expected substring
  | 
        
        
            | 
            | 
           1409 | 
                */
  | 
        
        
            | 
            | 
           1410 | 
               public function the_attribute_of_should_contain($attribute, $element, $selectortype, $text) {
  | 
        
        
            | 
            | 
           1411 | 
                   // Get the container node (exception if it doesn't exist).
  | 
        
        
            | 
            | 
           1412 | 
                   $containernode = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           1413 | 
                   $value = $containernode->getAttribute($attribute);
  | 
        
        
            | 
            | 
           1414 | 
                   if ($value == null) {
  | 
        
        
            | 
            | 
           1415 | 
                       throw new ExpectationException('The attribute "' . $attribute. '" does not exist',
  | 
        
        
            | 
            | 
           1416 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           1417 | 
                   } else if (strpos($value, $text) === false) {
  | 
        
        
            | 
            | 
           1418 | 
                       throw new ExpectationException('The attribute "' . $attribute .
  | 
        
        
            | 
            | 
           1419 | 
                               '" does not contain "' . $text . '" (actual value: "' . $value . '")',
  | 
        
        
            | 
            | 
           1420 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           1421 | 
                   }
  | 
        
        
            | 
            | 
           1422 | 
               }
  | 
        
        
            | 
            | 
           1423 | 
              | 
        
        
            | 
            | 
           1424 | 
               /**
  | 
        
        
            | 
            | 
           1425 | 
                * Checks that the attribute on the given element does not contain the specified text.
  | 
        
        
            | 
            | 
           1426 | 
                *
  | 
        
        
            | 
            | 
           1427 | 
                * @Then /^the "(?P<attribute_string>[^"]*)" attribute of "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not contain "(?P<text_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           1428 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1429 | 
                * @param string $attribute Name of attribute
  | 
        
        
            | 
            | 
           1430 | 
                * @param string $element The locator of the specified selector
  | 
        
        
            | 
            | 
           1431 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1432 | 
                * @param string $text Expected substring
  | 
        
        
            | 
            | 
           1433 | 
                */
  | 
        
        
            | 
            | 
           1434 | 
               public function the_attribute_of_should_not_contain($attribute, $element, $selectortype, $text) {
  | 
        
        
            | 
            | 
           1435 | 
                   // Get the container node (exception if it doesn't exist).
  | 
        
        
            | 
            | 
           1436 | 
                   $containernode = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           1437 | 
                   $value = $containernode->getAttribute($attribute);
  | 
        
        
            | 
            | 
           1438 | 
                   if ($value == null) {
  | 
        
        
            | 
            | 
           1439 | 
                       throw new ExpectationException('The attribute "' . $attribute. '" does not exist',
  | 
        
        
            | 
            | 
           1440 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           1441 | 
                   } else if (strpos($value, $text) !== false) {
  | 
        
        
            | 
            | 
           1442 | 
                       throw new ExpectationException('The attribute "' . $attribute .
  | 
        
        
            | 
            | 
           1443 | 
                               '" contains "' . $text . '" (value: "' . $value . '")',
  | 
        
        
            | 
            | 
           1444 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           1445 | 
                   }
  | 
        
        
            | 
            | 
           1446 | 
               }
  | 
        
        
            | 
            | 
           1447 | 
              | 
        
        
            | 
            | 
           1448 | 
               /**
  | 
        
        
            | 
            | 
           1449 | 
                * Checks the provided value exists in specific row/column of table.
  | 
        
        
            | 
            | 
           1450 | 
                *
  | 
        
        
            | 
            | 
           1451 | 
                * @Then /^"(?P<row_string>[^"]*)" row "(?P<column_string>[^"]*)" column of "(?P<table_string>[^"]*)" table should contain "(?P<value_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           1452 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           1453 | 
                * @param string $row row text which will be looked in.
  | 
        
        
            | 
            | 
           1454 | 
                * @param string $column column text to search (or numeric value for the column position)
  | 
        
        
            | 
            | 
           1455 | 
                * @param string $table table id/class/caption
  | 
        
        
            | 
            | 
           1456 | 
                * @param string $value text to check.
  | 
        
        
            | 
            | 
           1457 | 
                */
  | 
        
        
            | 
            | 
           1458 | 
               public function row_column_of_table_should_contain($row, $column, $table, $value) {
  | 
        
        
            | 
            | 
           1459 | 
                   $tablenode = $this->get_selected_node('table', $table);
  | 
        
        
            | 
            | 
           1460 | 
                   $tablexpath = $tablenode->getXpath();
  | 
        
        
            | 
            | 
           1461 | 
              | 
        
        
            | 
            | 
           1462 | 
                   $rowliteral = behat_context_helper::escape($row);
  | 
        
        
            | 
            | 
           1463 | 
                   $valueliteral = behat_context_helper::escape($value);
  | 
        
        
            | 
            | 
           1464 | 
              | 
        
        
           | 11 | 
           efrain | 
           1465 | 
                   $columnpositionxpath = $this->get_table_column_xpath($table, $column);
  | 
        
        
           | 1 | 
           efrain | 
           1466 | 
              | 
        
        
            | 
            | 
           1467 | 
                   // Check if value exists in specific row/column.
  | 
        
        
            | 
            | 
           1468 | 
                   // Get row xpath.
  | 
        
        
            | 
            | 
           1469 | 
                   // Some drivers make XPath relative to the current context, so use descendant.
  | 
        
        
            | 
            | 
           1470 | 
                   $rowxpath = $tablexpath . "/tbody/tr[descendant::*[@class='rowtitle'][normalize-space(.)=" . $rowliteral . "] | " . "
  | 
        
        
           | 1441 | 
           ariadna | 
           1471 | 
                       descendant::th[contains(normalize-space(.)," . $rowliteral . ")] | " . "
  | 
        
        
            | 
            | 
           1472 | 
                       descendant::td[contains(normalize-space(.)," . $rowliteral . ")]]";
  | 
        
        
           | 1 | 
           efrain | 
           1473 | 
              | 
        
        
            | 
            | 
           1474 | 
                   $columnvaluexpath = $rowxpath . $columnpositionxpath . "[contains(normalize-space(.)," . $valueliteral . ")]";
  | 
        
        
            | 
            | 
           1475 | 
              | 
        
        
            | 
            | 
           1476 | 
                   // Looks for the requested node inside the container node.
  | 
        
        
            | 
            | 
           1477 | 
                   $coumnnode = $this->getSession()->getDriver()->find($columnvaluexpath);
  | 
        
        
            | 
            | 
           1478 | 
                   if (empty($coumnnode)) {
  | 
        
        
            | 
            | 
           1479 | 
                       $locatorexceptionmsg = $value . '" in "' . $row . '" row with column "' . $column;
  | 
        
        
            | 
            | 
           1480 | 
                       throw new ElementNotFoundException($this->getSession(), "\n$columnvaluexpath\n\n".'Column value', null, $locatorexceptionmsg);
  | 
        
        
            | 
            | 
           1481 | 
                   }
  | 
        
        
            | 
            | 
           1482 | 
               }
  | 
        
        
            | 
            | 
           1483 | 
              | 
        
        
            | 
            | 
           1484 | 
               /**
  | 
        
        
            | 
            | 
           1485 | 
                * Checks the provided value should not exist in specific row/column of table.
  | 
        
        
            | 
            | 
           1486 | 
                *
  | 
        
        
            | 
            | 
           1487 | 
                * @Then /^"(?P<row_string>[^"]*)" row "(?P<column_string>[^"]*)" column of "(?P<table_string>[^"]*)" table should not contain "(?P<value_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           1488 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           1489 | 
                * @param string $row row text which will be looked in.
  | 
        
        
            | 
            | 
           1490 | 
                * @param string $column column text to search
  | 
        
        
            | 
            | 
           1491 | 
                * @param string $table table id/class/caption
  | 
        
        
            | 
            | 
           1492 | 
                * @param string $value text to check.
  | 
        
        
            | 
            | 
           1493 | 
                */
  | 
        
        
            | 
            | 
           1494 | 
               public function row_column_of_table_should_not_contain($row, $column, $table, $value) {
  | 
        
        
            | 
            | 
           1495 | 
                   try {
  | 
        
        
            | 
            | 
           1496 | 
                       $this->row_column_of_table_should_contain($row, $column, $table, $value);
  | 
        
        
            | 
            | 
           1497 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           1498 | 
                       // Table row/column doesn't contain this value. Nothing to do.
  | 
        
        
            | 
            | 
           1499 | 
                       return;
  | 
        
        
            | 
            | 
           1500 | 
                   }
  | 
        
        
            | 
            | 
           1501 | 
                   // Throw exception if found.
  | 
        
        
            | 
            | 
           1502 | 
                   throw new ExpectationException(
  | 
        
        
            | 
            | 
           1503 | 
                       '"' . $column . '" with value "' . $value . '" is present in "' . $row . '"  row for table "' . $table . '"',
  | 
        
        
            | 
            | 
           1504 | 
                       $this->getSession()
  | 
        
        
            | 
            | 
           1505 | 
                   );
  | 
        
        
            | 
            | 
           1506 | 
               }
  | 
        
        
            | 
            | 
           1507 | 
              | 
        
        
            | 
            | 
           1508 | 
               /**
  | 
        
        
           | 11 | 
           efrain | 
           1509 | 
                * Get xpath for a row child that corresponds to the specified column header
  | 
        
        
            | 
            | 
           1510 | 
                *
  | 
        
        
            | 
            | 
           1511 | 
                * @param string $table table identifier that can be used with 'table' node selector (i.e. table title or CSS class)
  | 
        
        
            | 
            | 
           1512 | 
                * @param string $column either text in the column header or the column number, such as -1-, -2-, etc
  | 
        
        
            | 
            | 
           1513 | 
                *      When matching the column header it has to be either exact match of the whole header or an exact
  | 
        
        
            | 
            | 
           1514 | 
                *      match of a text inside a link in the header.
  | 
        
        
            | 
            | 
           1515 | 
                *      For example, to match "<a>First name</a> / <a>Last name</a>" you need to specify either "First name" or "Last name"
  | 
        
        
            | 
            | 
           1516 | 
                * @return string
  | 
        
        
            | 
            | 
           1517 | 
                */
  | 
        
        
            | 
            | 
           1518 | 
               protected function get_table_column_xpath(string $table, string $column): string {
  | 
        
        
            | 
            | 
           1519 | 
                   $tablenode = $this->get_selected_node('table', $table);
  | 
        
        
            | 
            | 
           1520 | 
                   $tablexpath = $tablenode->getXpath();
  | 
        
        
            | 
            | 
           1521 | 
                   $columnliteral = behat_context_helper::escape($column);
  | 
        
        
            | 
            | 
           1522 | 
                   if (preg_match('/^-?(\d+)-?$/', $column, $columnasnumber)) {
  | 
        
        
            | 
            | 
           1523 | 
                       // Column indicated as a number, just use it as position of the column.
  | 
        
        
            | 
            | 
           1524 | 
                       $columnpositionxpath = "/child::*[position() = {$columnasnumber[1]}]";
  | 
        
        
            | 
            | 
           1525 | 
                   } else {
  | 
        
        
            | 
            | 
           1526 | 
                       // Header can be in thead or tbody (first row), following xpath should work.
  | 
        
        
            | 
            | 
           1527 | 
                       $theadheaderxpath = "thead/tr[1]/th[(normalize-space(.)={$columnliteral} or a[normalize-space(text())=" .
  | 
        
        
            | 
            | 
           1528 | 
                               $columnliteral . "] or div[normalize-space(text())={$columnliteral}])]";
  | 
        
        
            | 
            | 
           1529 | 
                       $tbodyheaderxpath = "tbody/tr[1]/td[(normalize-space(.)={$columnliteral} or a[normalize-space(text())=" .
  | 
        
        
            | 
            | 
           1530 | 
                               $columnliteral . "] or div[normalize-space(text())={$columnliteral}])]";
  | 
        
        
            | 
            | 
           1531 | 
              | 
        
        
            | 
            | 
           1532 | 
                       // Check if column exists.
  | 
        
        
            | 
            | 
           1533 | 
                       $columnheaderxpath = "{$tablexpath}[{$theadheaderxpath} | {$tbodyheaderxpath}]";
  | 
        
        
            | 
            | 
           1534 | 
                       $columnheader = $this->getSession()->getDriver()->find($columnheaderxpath);
  | 
        
        
            | 
            | 
           1535 | 
                       if (empty($columnheader)) {
  | 
        
        
            | 
            | 
           1536 | 
                           if (strpos($column, '/') !== false) {
  | 
        
        
            | 
            | 
           1537 | 
                               // We are not able to match headers consisting of several links, such as "First name / Last name".
  | 
        
        
            | 
            | 
           1538 | 
                               // Instead we can match "First name" or "Last name" or "-1-" (column number).
  | 
        
        
            | 
            | 
           1539 | 
                               throw new Exception("Column matching locator \"$column\" not found. ".
  | 
        
        
            | 
            | 
           1540 | 
                                   "If the column header contains multiple links, specify only one of the link texts. ".
  | 
        
        
            | 
            | 
           1541 | 
                                   "Otherwise, use the column number as the locator");
  | 
        
        
            | 
            | 
           1542 | 
                           }
  | 
        
        
            | 
            | 
           1543 | 
                           $columnexceptionmsg = $column . '" in table "' . $table . '"';
  | 
        
        
            | 
            | 
           1544 | 
                           throw new ElementNotFoundException($this->getSession(), "\n$columnheaderxpath\n\n".'Column',
  | 
        
        
            | 
            | 
           1545 | 
                               null, $columnexceptionmsg);
  | 
        
        
            | 
            | 
           1546 | 
                       }
  | 
        
        
            | 
            | 
           1547 | 
                       // Following conditions were considered before finding column count.
  | 
        
        
            | 
            | 
           1548 | 
                       // 1. Table header can be in thead/tr/th or tbody/tr/td[1].
  | 
        
        
            | 
            | 
           1549 | 
                       // 2. First column can have th (Gradebook -> user report), so having lenient sibling check.
  | 
        
        
            | 
            | 
           1550 | 
                       $columnpositionxpath = "/child::*[position() = count({$tablexpath}/{$theadheaderxpath}" .
  | 
        
        
            | 
            | 
           1551 | 
                           "/preceding-sibling::*) + 1]";
  | 
        
        
            | 
            | 
           1552 | 
                   }
  | 
        
        
            | 
            | 
           1553 | 
                   return $columnpositionxpath;
  | 
        
        
            | 
            | 
           1554 | 
               }
  | 
        
        
            | 
            | 
           1555 | 
              | 
        
        
            | 
            | 
           1556 | 
               /**
  | 
        
        
            | 
            | 
           1557 | 
                * Find a table row where each of the specified columns matches and throw exception if not found
  | 
        
        
            | 
            | 
           1558 | 
                *
  | 
        
        
            | 
            | 
           1559 | 
                * @param string $table table locator
  | 
        
        
            | 
            | 
           1560 | 
                * @param array $cells key is the column locator (name or index such as '-1-') and value is the text contents of the table cell
  | 
        
        
            | 
            | 
           1561 | 
                */
  | 
        
        
            | 
            | 
           1562 | 
               protected function ensure_table_row_exists(string $table, array $cells): void {
  | 
        
        
            | 
            | 
           1563 | 
                   $tablenode = $this->get_selected_node('table', $table);
  | 
        
        
            | 
            | 
           1564 | 
                   $tablexpath = $tablenode->getXpath();
  | 
        
        
            | 
            | 
           1565 | 
              | 
        
        
            | 
            | 
           1566 | 
                   $columnconditions = [];
  | 
        
        
            | 
            | 
           1567 | 
                   foreach ($cells as $columnname => $value) {
  | 
        
        
            | 
            | 
           1568 | 
                       $valueliteral = behat_context_helper::escape($value);
  | 
        
        
            | 
            | 
           1569 | 
                       $columnpositionxpath = $this->get_table_column_xpath($table, $columnname);
  | 
        
        
            | 
            | 
           1570 | 
                       $columnconditions[] = '.' . $columnpositionxpath . "[contains(normalize-space(.)," . $valueliteral . ")]";
  | 
        
        
            | 
            | 
           1571 | 
                   }
  | 
        
        
            | 
            | 
           1572 | 
                   $rowxpath = $tablexpath . "/tbody/tr[" . join(' and ', $columnconditions) . ']';
  | 
        
        
            | 
            | 
           1573 | 
              | 
        
        
            | 
            | 
           1574 | 
                   $rownode = $this->getSession()->getDriver()->find($rowxpath);
  | 
        
        
            | 
            | 
           1575 | 
                   if (empty($rownode)) {
  | 
        
        
            | 
            | 
           1576 | 
                       $rowlocator = array_map(fn($k) => "{$k} => {$cells[$k]}", array_keys($cells));
  | 
        
        
            | 
            | 
           1577 | 
                       throw new ElementNotFoundException($this->getSession(), "\n$rowxpath\n\n".'Table row', null, join(', ', $rowlocator));
  | 
        
        
            | 
            | 
           1578 | 
                   }
  | 
        
        
            | 
            | 
           1579 | 
               }
  | 
        
        
            | 
            | 
           1580 | 
              | 
        
        
            | 
            | 
           1581 | 
               /**
  | 
        
        
            | 
            | 
           1582 | 
                * Find a table row where each of the specified columns matches and throw exception if found
  | 
        
        
            | 
            | 
           1583 | 
                *
  | 
        
        
            | 
            | 
           1584 | 
                * @param string $table table locator
  | 
        
        
            | 
            | 
           1585 | 
                * @param array $cells key is the column locator (name or index such as '-1-') and value is the text contents of the table cell
  | 
        
        
            | 
            | 
           1586 | 
                */
  | 
        
        
            | 
            | 
           1587 | 
               protected function ensure_table_row_does_not_exist(string $table, array $cells): void {
  | 
        
        
            | 
            | 
           1588 | 
                   try {
  | 
        
        
            | 
            | 
           1589 | 
                       $this->ensure_table_row_exists($table, $cells);
  | 
        
        
            | 
            | 
           1590 | 
                       // Throw exception if found.
  | 
        
        
            | 
            | 
           1591 | 
                   } catch (ElementNotFoundException $e) {
  | 
        
        
            | 
            | 
           1592 | 
                       // Table row/column doesn't contain this value. Nothing to do.
  | 
        
        
            | 
            | 
           1593 | 
                       return;
  | 
        
        
            | 
            | 
           1594 | 
                   }
  | 
        
        
            | 
            | 
           1595 | 
                   $rowlocator = array_map(fn($k) => "{$k} => {$cells[$k]}", array_keys($cells));
  | 
        
        
            | 
            | 
           1596 | 
                   throw new ExpectationException('Table row "' . join(', ', $rowlocator) .
  | 
        
        
            | 
            | 
           1597 | 
                       '" is present in the table "' . $table . '"', $this->getSession()
  | 
        
        
            | 
            | 
           1598 | 
                   );
  | 
        
        
            | 
            | 
           1599 | 
               }
  | 
        
        
            | 
            | 
           1600 | 
              | 
        
        
            | 
            | 
           1601 | 
               /**
  | 
        
        
           | 1 | 
           efrain | 
           1602 | 
                * Checks that the provided value exist in table.
  | 
        
        
            | 
            | 
           1603 | 
                *
  | 
        
        
            | 
            | 
           1604 | 
                * First row may contain column headers or numeric indexes of the columns
  | 
        
        
            | 
            | 
           1605 | 
                * (syntax -1- is also considered to be column index). Column indexes are
  | 
        
        
            | 
            | 
           1606 | 
                * useful in case of multirow headers and/or presence of cells with colspan.
  | 
        
        
            | 
            | 
           1607 | 
                *
  | 
        
        
            | 
            | 
           1608 | 
                * @Then /^the following should exist in the "(?P<table_string>[^"]*)" table:$/
  | 
        
        
            | 
            | 
           1609 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1610 | 
                * @param string $table name of table
  | 
        
        
            | 
            | 
           1611 | 
                * @param TableNode $data table with first row as header and following values
  | 
        
        
            | 
            | 
           1612 | 
                *        | Header 1 | Header 2 | Header 3 |
  | 
        
        
            | 
            | 
           1613 | 
                *        | Value 1 | Value 2 | Value 3|
  | 
        
        
            | 
            | 
           1614 | 
                */
  | 
        
        
            | 
            | 
           1615 | 
               public function following_should_exist_in_the_table($table, TableNode $data) {
  | 
        
        
            | 
            | 
           1616 | 
                   $datahash = $data->getHash();
  | 
        
        
           | 11 | 
           efrain | 
           1617 | 
                   if ($datahash && count($data->getRow(0)) != count($datahash[0])) {
  | 
        
        
            | 
            | 
           1618 | 
                       // Check that the number of columns in the hash is the same as the number of the columns in the first row.
  | 
        
        
            | 
            | 
           1619 | 
                       throw new coding_exception('Table contains duplicate column headers');
  | 
        
        
            | 
            | 
           1620 | 
                   }
  | 
        
        
           | 1 | 
           efrain | 
           1621 | 
              | 
        
        
            | 
            | 
           1622 | 
                   foreach ($datahash as $row) {
  | 
        
        
           | 11 | 
           efrain | 
           1623 | 
                       $this->ensure_table_row_exists($table, $row);
  | 
        
        
           | 1 | 
           efrain | 
           1624 | 
                   }
  | 
        
        
            | 
            | 
           1625 | 
               }
  | 
        
        
            | 
            | 
           1626 | 
              | 
        
        
            | 
            | 
           1627 | 
               /**
  | 
        
        
            | 
            | 
           1628 | 
                * Checks that the provided values do not exist in a table.
  | 
        
        
            | 
            | 
           1629 | 
                *
  | 
        
        
           | 11 | 
           efrain | 
           1630 | 
                * If there are more than two columns, we check that NEITHER of the columns 2..n match
  | 
        
        
            | 
            | 
           1631 | 
                * in the row where the first column matches
  | 
        
        
            | 
            | 
           1632 | 
                *
  | 
        
        
           | 1 | 
           efrain | 
           1633 | 
                * @Then /^the following should not exist in the "(?P<table_string>[^"]*)" table:$/
  | 
        
        
            | 
            | 
           1634 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1635 | 
                * @param string $table name of table
  | 
        
        
            | 
            | 
           1636 | 
                * @param TableNode $data table with first row as header and following values
  | 
        
        
            | 
            | 
           1637 | 
                *        | Header 1 | Header 2 | Header 3 |
  | 
        
        
            | 
            | 
           1638 | 
                *        | Value 1 | Value 2 | Value 3|
  | 
        
        
            | 
            | 
           1639 | 
                */
  | 
        
        
            | 
            | 
           1640 | 
               public function following_should_not_exist_in_the_table($table, TableNode $data) {
  | 
        
        
            | 
            | 
           1641 | 
                   $datahash = $data->getHash();
  | 
        
        
           | 11 | 
           efrain | 
           1642 | 
                   if ($datahash && count($data->getRow(0)) != count($datahash[0])) {
  | 
        
        
            | 
            | 
           1643 | 
                       // Check that the number of columns in the hash is the same as the number of the columns in the first row.
  | 
        
        
            | 
            | 
           1644 | 
                       throw new coding_exception('Table contains duplicate column headers');
  | 
        
        
            | 
            | 
           1645 | 
                   }
  | 
        
        
           | 1 | 
           efrain | 
           1646 | 
              | 
        
        
            | 
            | 
           1647 | 
                   foreach ($datahash as $value) {
  | 
        
        
           | 11 | 
           efrain | 
           1648 | 
                       if (count($value) > 2) {
  | 
        
        
            | 
            | 
           1649 | 
                           // When there are more than two columns, what we really want to check is that for the rows
  | 
        
        
            | 
            | 
           1650 | 
                           // where the first column matches, NEITHER of the other columns match.
  | 
        
        
            | 
            | 
           1651 | 
                           $columns = array_keys($value);
  | 
        
        
            | 
            | 
           1652 | 
                           for ($i = 1; $i < count($columns); $i++) {
  | 
        
        
            | 
            | 
           1653 | 
                               $this->ensure_table_row_does_not_exist($table, [
  | 
        
        
            | 
            | 
           1654 | 
                                   $columns[0] => $value[$columns[0]],
  | 
        
        
            | 
            | 
           1655 | 
                                   $columns[$i] => $value[$columns[$i]],
  | 
        
        
            | 
            | 
           1656 | 
                               ]);
  | 
        
        
            | 
            | 
           1657 | 
                           }
  | 
        
        
           | 1 | 
           efrain | 
           1658 | 
                       } else {
  | 
        
        
           | 11 | 
           efrain | 
           1659 | 
                           $this->ensure_table_row_does_not_exist($table, $value);
  | 
        
        
           | 1 | 
           efrain | 
           1660 | 
                       }
  | 
        
        
            | 
            | 
           1661 | 
                   }
  | 
        
        
            | 
            | 
           1662 | 
               }
  | 
        
        
            | 
            | 
           1663 | 
              | 
        
        
            | 
            | 
           1664 | 
               /**
  | 
        
        
            | 
            | 
           1665 | 
                * Given the text of a link, download the linked file and return the contents.
  | 
        
        
            | 
            | 
           1666 | 
                *
  | 
        
        
           | 1441 | 
           ariadna | 
           1667 | 
                * A helper method used by the steps in {@see behat_download}, and the legacy
  | 
        
        
            | 
            | 
           1668 | 
                * {@see following_should_download_bytes()} and {@see following_should_download_between_and_bytes()}.
  | 
        
        
           | 1 | 
           efrain | 
           1669 | 
                *
  | 
        
        
            | 
            | 
           1670 | 
                * @param string $link the text of the link.
  | 
        
        
           | 1441 | 
           ariadna | 
           1671 | 
                * @param string $containerlocator optional container element locator.
  | 
        
        
            | 
            | 
           1672 | 
                * @param string $containertype optional container element selector type.
  | 
        
        
            | 
            | 
           1673 | 
                *
  | 
        
        
           | 1 | 
           efrain | 
           1674 | 
                * @return string the content of the downloaded file.
  | 
        
        
            | 
            | 
           1675 | 
                */
  | 
        
        
           | 1441 | 
           ariadna | 
           1676 | 
               public function download_file_from_link(string $link, string $containerlocator = '', string $containertype = ''): string {
  | 
        
        
            | 
            | 
           1677 | 
              | 
        
        
           | 1 | 
           efrain | 
           1678 | 
                   // Find the link.
  | 
        
        
           | 1441 | 
           ariadna | 
           1679 | 
                   if ($containerlocator !== '' && $containertype !== '') {
  | 
        
        
            | 
            | 
           1680 | 
                       $linknode = $this->get_node_in_container('link', $link, $containertype, $containerlocator);
  | 
        
        
            | 
            | 
           1681 | 
                   } else {
  | 
        
        
            | 
            | 
           1682 | 
                       $linknode = $this->find_link($link);
  | 
        
        
            | 
            | 
           1683 | 
                   }
  | 
        
        
            | 
            | 
           1684 | 
              | 
        
        
           | 1 | 
           efrain | 
           1685 | 
                   $this->ensure_node_is_visible($linknode);
  | 
        
        
            | 
            | 
           1686 | 
              | 
        
        
            | 
            | 
           1687 | 
                   // Get the href and check it.
  | 
        
        
            | 
            | 
           1688 | 
                   $url = $linknode->getAttribute('href');
  | 
        
        
            | 
            | 
           1689 | 
                   if (!$url) {
  | 
        
        
            | 
            | 
           1690 | 
                       throw new ExpectationException('Download link does not have href attribute',
  | 
        
        
            | 
            | 
           1691 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           1692 | 
                   }
  | 
        
        
            | 
            | 
           1693 | 
                   if (!preg_match('~^https?://~', $url)) {
  | 
        
        
            | 
            | 
           1694 | 
                       throw new ExpectationException('Download link not an absolute URL: ' . $url,
  | 
        
        
            | 
            | 
           1695 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           1696 | 
                   }
  | 
        
        
            | 
            | 
           1697 | 
              | 
        
        
            | 
            | 
           1698 | 
                   // Download the URL and check the size.
  | 
        
        
            | 
            | 
           1699 | 
                   $session = $this->getSession()->getCookie('MoodleSession');
  | 
        
        
            | 
            | 
           1700 | 
                   return download_file_content($url, array('Cookie' => 'MoodleSession=' . $session));
  | 
        
        
            | 
            | 
           1701 | 
               }
  | 
        
        
            | 
            | 
           1702 | 
              | 
        
        
            | 
            | 
           1703 | 
               /**
  | 
        
        
            | 
            | 
           1704 | 
                * Downloads the file from a link on the page and checks the size.
  | 
        
        
            | 
            | 
           1705 | 
                *
  | 
        
        
           | 1441 | 
           ariadna | 
           1706 | 
                * Not recommended any more. The steps in {@see behat_download} are much better!
  | 
        
        
            | 
            | 
           1707 | 
                *
  | 
        
        
           | 1 | 
           efrain | 
           1708 | 
                * Only works if the link has an href attribute. Javascript downloads are
  | 
        
        
            | 
            | 
           1709 | 
                * not supported. Currently, the href must be an absolute URL.
  | 
        
        
            | 
            | 
           1710 | 
                *
  | 
        
        
            | 
            | 
           1711 | 
                * @Then /^following "(?P<link_string>[^"]*)" should download "(?P<expected_bytes>\d+)" bytes$/
  | 
        
        
            | 
            | 
           1712 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1713 | 
                * @param string $link the text of the link.
  | 
        
        
            | 
            | 
           1714 | 
                * @param number $expectedsize the expected file size in bytes.
  | 
        
        
            | 
            | 
           1715 | 
                */
  | 
        
        
            | 
            | 
           1716 | 
               public function following_should_download_bytes($link, $expectedsize) {
  | 
        
        
            | 
            | 
           1717 | 
                   $exception = new ExpectationException('Error while downloading data from ' . $link, $this->getSession());
  | 
        
        
            | 
            | 
           1718 | 
              | 
        
        
            | 
            | 
           1719 | 
                   // It will stop spinning once file is downloaded or time out.
  | 
        
        
            | 
            | 
           1720 | 
                   $result = $this->spin(
  | 
        
        
            | 
            | 
           1721 | 
                       function($context, $args) {
  | 
        
        
            | 
            | 
           1722 | 
                           $link = $args['link'];
  | 
        
        
            | 
            | 
           1723 | 
                           return $this->download_file_from_link($link);
  | 
        
        
            | 
            | 
           1724 | 
                       },
  | 
        
        
            | 
            | 
           1725 | 
                       array('link' => $link),
  | 
        
        
            | 
            | 
           1726 | 
                       behat_base::get_extended_timeout(),
  | 
        
        
            | 
            | 
           1727 | 
                       $exception
  | 
        
        
            | 
            | 
           1728 | 
                   );
  | 
        
        
            | 
            | 
           1729 | 
              | 
        
        
            | 
            | 
           1730 | 
                   // Check download size.
  | 
        
        
            | 
            | 
           1731 | 
                   $actualsize = (int)strlen($result);
  | 
        
        
            | 
            | 
           1732 | 
                   if ($actualsize !== (int)$expectedsize) {
  | 
        
        
            | 
            | 
           1733 | 
                       throw new ExpectationException('Downloaded data was ' . $actualsize .
  | 
        
        
            | 
            | 
           1734 | 
                               ' bytes, expecting ' . $expectedsize, $this->getSession());
  | 
        
        
            | 
            | 
           1735 | 
                   }
  | 
        
        
            | 
            | 
           1736 | 
               }
  | 
        
        
            | 
            | 
           1737 | 
              | 
        
        
            | 
            | 
           1738 | 
               /**
  | 
        
        
            | 
            | 
           1739 | 
                * Downloads the file from a link on the page and checks the size is in a given range.
  | 
        
        
            | 
            | 
           1740 | 
                *
  | 
        
        
           | 1441 | 
           ariadna | 
           1741 | 
                * Not recommended any more. The steps in {@see behat_download} are much better!
  | 
        
        
            | 
            | 
           1742 | 
                *
  | 
        
        
           | 1 | 
           efrain | 
           1743 | 
                * Only works if the link has an href attribute. Javascript downloads are
  | 
        
        
            | 
            | 
           1744 | 
                * not supported. Currently, the href must be an absolute URL.
  | 
        
        
            | 
            | 
           1745 | 
                *
  | 
        
        
            | 
            | 
           1746 | 
                * The range includes the endpoints. That is, a 10 byte file in considered to
  | 
        
        
            | 
            | 
           1747 | 
                * be between "5" and "10" bytes, and between "10" and "20" bytes.
  | 
        
        
            | 
            | 
           1748 | 
                *
  | 
        
        
            | 
            | 
           1749 | 
                * @Then /^following "(?P<link_string>[^"]*)" should download between "(?P<min_bytes>\d+)" and "(?P<max_bytes>\d+)" bytes$/
  | 
        
        
           | 1441 | 
           ariadna | 
           1750 | 
                *
  | 
        
        
           | 1 | 
           efrain | 
           1751 | 
                * @param string $link the text of the link.
  | 
        
        
            | 
            | 
           1752 | 
                * @param number $minexpectedsize the minimum expected file size in bytes.
  | 
        
        
            | 
            | 
           1753 | 
                * @param number $maxexpectedsize the maximum expected file size in bytes.
  | 
        
        
           | 1441 | 
           ariadna | 
           1754 | 
                * @throws ExpectationException
  | 
        
        
           | 1 | 
           efrain | 
           1755 | 
                */
  | 
        
        
            | 
            | 
           1756 | 
               public function following_should_download_between_and_bytes($link, $minexpectedsize, $maxexpectedsize) {
  | 
        
        
            | 
            | 
           1757 | 
                   // If the minimum is greater than the maximum then swap the values.
  | 
        
        
            | 
            | 
           1758 | 
                   if ((int)$minexpectedsize > (int)$maxexpectedsize) {
  | 
        
        
           | 1441 | 
           ariadna | 
           1759 | 
                       [$minexpectedsize, $maxexpectedsize] = [$maxexpectedsize, $minexpectedsize];
  | 
        
        
           | 1 | 
           efrain | 
           1760 | 
                   }
  | 
        
        
            | 
            | 
           1761 | 
              | 
        
        
            | 
            | 
           1762 | 
                   $exception = new ExpectationException('Error while downloading data from ' . $link, $this->getSession());
  | 
        
        
            | 
            | 
           1763 | 
              | 
        
        
            | 
            | 
           1764 | 
                   // It will stop spinning once file is downloaded or time out.
  | 
        
        
            | 
            | 
           1765 | 
                   $result = $this->spin(
  | 
        
        
            | 
            | 
           1766 | 
                       function($context, $args) {
  | 
        
        
            | 
            | 
           1767 | 
                           $link = $args['link'];
  | 
        
        
            | 
            | 
           1768 | 
              | 
        
        
            | 
            | 
           1769 | 
                           return $this->download_file_from_link($link);
  | 
        
        
            | 
            | 
           1770 | 
                       },
  | 
        
        
            | 
            | 
           1771 | 
                       array('link' => $link),
  | 
        
        
            | 
            | 
           1772 | 
                       behat_base::get_extended_timeout(),
  | 
        
        
            | 
            | 
           1773 | 
                       $exception
  | 
        
        
            | 
            | 
           1774 | 
                   );
  | 
        
        
            | 
            | 
           1775 | 
              | 
        
        
            | 
            | 
           1776 | 
                   // Check download size.
  | 
        
        
            | 
            | 
           1777 | 
                   $actualsize = (int)strlen($result);
  | 
        
        
            | 
            | 
           1778 | 
                   if ($actualsize < $minexpectedsize || $actualsize > $maxexpectedsize) {
  | 
        
        
            | 
            | 
           1779 | 
                       throw new ExpectationException('Downloaded data was ' . $actualsize .
  | 
        
        
            | 
            | 
           1780 | 
                               ' bytes, expecting between ' . $minexpectedsize . ' and ' .
  | 
        
        
            | 
            | 
           1781 | 
                               $maxexpectedsize, $this->getSession());
  | 
        
        
            | 
            | 
           1782 | 
                   }
  | 
        
        
            | 
            | 
           1783 | 
               }
  | 
        
        
            | 
            | 
           1784 | 
              | 
        
        
            | 
            | 
           1785 | 
               /**
  | 
        
        
            | 
            | 
           1786 | 
                * Checks that the image on the page is the same as one of the fixture files
  | 
        
        
            | 
            | 
           1787 | 
                *
  | 
        
        
            | 
            | 
           1788 | 
                * @Then /^the image at "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be identical to "(?P<filepath_string>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           1789 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1790 | 
                * @param string $element The locator of the image
  | 
        
        
            | 
            | 
           1791 | 
                * @param string $selectortype The selector type
  | 
        
        
            | 
            | 
           1792 | 
                * @param string $filepath path to the fixture file
  | 
        
        
            | 
            | 
           1793 | 
                */
  | 
        
        
            | 
            | 
           1794 | 
               public function the_image_at_should_be_identical_to($element, $selectortype, $filepath) {
  | 
        
        
            | 
            | 
           1795 | 
                   global $CFG;
  | 
        
        
            | 
            | 
           1796 | 
              | 
        
        
            | 
            | 
           1797 | 
                   // Get the container node (exception if it doesn't exist).
  | 
        
        
            | 
            | 
           1798 | 
                   $containernode = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           1799 | 
                   $url = $containernode->getAttribute('src');
  | 
        
        
            | 
            | 
           1800 | 
                   if ($url == null) {
  | 
        
        
            | 
            | 
           1801 | 
                       throw new ExpectationException('Element does not have src attribute',
  | 
        
        
            | 
            | 
           1802 | 
                           $this->getSession());
  | 
        
        
            | 
            | 
           1803 | 
                   }
  | 
        
        
            | 
            | 
           1804 | 
                   $session = $this->getSession()->getCookie('MoodleSession');
  | 
        
        
            | 
            | 
           1805 | 
                   $content = download_file_content($url, array('Cookie' => 'MoodleSession=' . $session));
  | 
        
        
            | 
            | 
           1806 | 
              | 
        
        
            | 
            | 
           1807 | 
                   // Get the content of the fixture file.
  | 
        
        
            | 
            | 
           1808 | 
                   // Replace 'admin/' if it is in start of path with $CFG->admin .
  | 
        
        
            | 
            | 
           1809 | 
                   if (substr($filepath, 0, 6) === 'admin/') {
  | 
        
        
            | 
            | 
           1810 | 
                       $filepath = $CFG->admin . DIRECTORY_SEPARATOR . substr($filepath, 6);
  | 
        
        
            | 
            | 
           1811 | 
                   }
  | 
        
        
            | 
            | 
           1812 | 
                   $filepath = str_replace('/', DIRECTORY_SEPARATOR, $filepath);
  | 
        
        
            | 
            | 
           1813 | 
                   $filepath = $CFG->dirroot . DIRECTORY_SEPARATOR . $filepath;
  | 
        
        
            | 
            | 
           1814 | 
                   if (!is_readable($filepath)) {
  | 
        
        
            | 
            | 
           1815 | 
                       throw new ExpectationException('The file to compare to does not exist.', $this->getSession());
  | 
        
        
            | 
            | 
           1816 | 
                   }
  | 
        
        
            | 
            | 
           1817 | 
                   $expectedcontent = file_get_contents($filepath);
  | 
        
        
            | 
            | 
           1818 | 
              | 
        
        
            | 
            | 
           1819 | 
                   if ($content !== $expectedcontent) {
  | 
        
        
            | 
            | 
           1820 | 
                       throw new ExpectationException('Image is not identical to the fixture. Received ' .
  | 
        
        
            | 
            | 
           1821 | 
                       strlen($content) . ' bytes and expected ' . strlen($expectedcontent) . ' bytes', $this->getSession());
  | 
        
        
            | 
            | 
           1822 | 
                   }
  | 
        
        
            | 
            | 
           1823 | 
               }
  | 
        
        
            | 
            | 
           1824 | 
              | 
        
        
            | 
            | 
           1825 | 
               /**
  | 
        
        
            | 
            | 
           1826 | 
                * Prepare to detect whether or not a new page has loaded (or the same page reloaded) some time in the future.
  | 
        
        
            | 
            | 
           1827 | 
                *
  | 
        
        
            | 
            | 
           1828 | 
                * @Given /^I start watching to see if a new page loads$/
  | 
        
        
            | 
            | 
           1829 | 
                */
  | 
        
        
            | 
            | 
           1830 | 
               public function i_start_watching_to_see_if_a_new_page_loads() {
  | 
        
        
            | 
            | 
           1831 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           1832 | 
                       throw new DriverException('Page load detection requires JavaScript.');
  | 
        
        
            | 
            | 
           1833 | 
                   }
  | 
        
        
            | 
            | 
           1834 | 
              | 
        
        
            | 
            | 
           1835 | 
                   $session = $this->getSession();
  | 
        
        
            | 
            | 
           1836 | 
              | 
        
        
            | 
            | 
           1837 | 
                   if ($this->pageloaddetectionrunning || $session->getPage()->find('xpath', $this->get_page_load_xpath())) {
  | 
        
        
            | 
            | 
           1838 | 
                       // If we find this node at this point we are already watching for a reload and the behat steps
  | 
        
        
            | 
            | 
           1839 | 
                       // are out of order. We will treat this as an error - really it needs to be fixed as it indicates a problem.
  | 
        
        
            | 
            | 
           1840 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           1841 | 
                           'Page load expectation error: page reloads are already been watched for.', $session);
  | 
        
        
            | 
            | 
           1842 | 
                   }
  | 
        
        
            | 
            | 
           1843 | 
              | 
        
        
            | 
            | 
           1844 | 
                   $this->pageloaddetectionrunning = true;
  | 
        
        
            | 
            | 
           1845 | 
              | 
        
        
            | 
            | 
           1846 | 
                   $this->execute_script(
  | 
        
        
            | 
            | 
           1847 | 
                       'var span = document.createElement("span");
  | 
        
        
            | 
            | 
           1848 | 
                       span.setAttribute("data-rel", "' . self::PAGE_LOAD_DETECTION_STRING . '");
  | 
        
        
            | 
            | 
           1849 | 
                       span.setAttribute("style", "display: none;");
  | 
        
        
            | 
            | 
           1850 | 
                       document.body.appendChild(span);'
  | 
        
        
            | 
            | 
           1851 | 
                   );
  | 
        
        
            | 
            | 
           1852 | 
               }
  | 
        
        
            | 
            | 
           1853 | 
              | 
        
        
            | 
            | 
           1854 | 
               /**
  | 
        
        
            | 
            | 
           1855 | 
                * Verify that a new page has loaded (or the same page has reloaded) since the
  | 
        
        
            | 
            | 
           1856 | 
                * last "I start watching to see if a new page loads" step.
  | 
        
        
            | 
            | 
           1857 | 
                *
  | 
        
        
            | 
            | 
           1858 | 
                * @Given /^a new page should have loaded since I started watching$/
  | 
        
        
            | 
            | 
           1859 | 
                */
  | 
        
        
            | 
            | 
           1860 | 
               public function a_new_page_should_have_loaded_since_i_started_watching() {
  | 
        
        
            | 
            | 
           1861 | 
                   $session = $this->getSession();
  | 
        
        
            | 
            | 
           1862 | 
              | 
        
        
            | 
            | 
           1863 | 
                   // Make sure page load tracking was started.
  | 
        
        
            | 
            | 
           1864 | 
                   if (!$this->pageloaddetectionrunning) {
  | 
        
        
            | 
            | 
           1865 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           1866 | 
                           'Page load expectation error: page load tracking was not started.', $session);
  | 
        
        
            | 
            | 
           1867 | 
                   }
  | 
        
        
            | 
            | 
           1868 | 
              | 
        
        
            | 
            | 
           1869 | 
                   // As the node is inserted by code above it is either there or not, and we do not need spin and it is safe
  | 
        
        
            | 
            | 
           1870 | 
                   // to use the native API here which is great as exception handling (the alternative is slow).
  | 
        
        
            | 
            | 
           1871 | 
                   if ($session->getPage()->find('xpath', $this->get_page_load_xpath())) {
  | 
        
        
            | 
            | 
           1872 | 
                       // We don't want to find this node, if we do we have an error.
  | 
        
        
            | 
            | 
           1873 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           1874 | 
                           'Page load expectation error: a new page has not been loaded when it should have been.', $session);
  | 
        
        
            | 
            | 
           1875 | 
                   }
  | 
        
        
            | 
            | 
           1876 | 
              | 
        
        
            | 
            | 
           1877 | 
                   // Cancel the tracking of pageloaddetectionrunning.
  | 
        
        
            | 
            | 
           1878 | 
                   $this->pageloaddetectionrunning = false;
  | 
        
        
            | 
            | 
           1879 | 
               }
  | 
        
        
            | 
            | 
           1880 | 
              | 
        
        
            | 
            | 
           1881 | 
               /**
  | 
        
        
            | 
            | 
           1882 | 
                * Verify that a new page has not loaded (or the same page has reloaded) since the
  | 
        
        
            | 
            | 
           1883 | 
                * last "I start watching to see if a new page loads" step.
  | 
        
        
            | 
            | 
           1884 | 
                *
  | 
        
        
            | 
            | 
           1885 | 
                * @Given /^a new page should not have loaded since I started watching$/
  | 
        
        
            | 
            | 
           1886 | 
                */
  | 
        
        
            | 
            | 
           1887 | 
               public function a_new_page_should_not_have_loaded_since_i_started_watching() {
  | 
        
        
            | 
            | 
           1888 | 
                   $session = $this->getSession();
  | 
        
        
            | 
            | 
           1889 | 
              | 
        
        
            | 
            | 
           1890 | 
                   // Make sure page load tracking was started.
  | 
        
        
            | 
            | 
           1891 | 
                   if (!$this->pageloaddetectionrunning) {
  | 
        
        
            | 
            | 
           1892 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           1893 | 
                           'Page load expectation error: page load tracking was not started.', $session);
  | 
        
        
            | 
            | 
           1894 | 
                   }
  | 
        
        
            | 
            | 
           1895 | 
              | 
        
        
            | 
            | 
           1896 | 
                   // We use our API here as we can use the exception handling provided by it.
  | 
        
        
            | 
            | 
           1897 | 
                   $this->find(
  | 
        
        
            | 
            | 
           1898 | 
                       'xpath',
  | 
        
        
            | 
            | 
           1899 | 
                       $this->get_page_load_xpath(),
  | 
        
        
            | 
            | 
           1900 | 
                       new ExpectationException(
  | 
        
        
            | 
            | 
           1901 | 
                           'Page load expectation error: A new page has been loaded when it should not have been.',
  | 
        
        
            | 
            | 
           1902 | 
                           $this->getSession()
  | 
        
        
            | 
            | 
           1903 | 
                       )
  | 
        
        
            | 
            | 
           1904 | 
                   );
  | 
        
        
            | 
            | 
           1905 | 
               }
  | 
        
        
            | 
            | 
           1906 | 
              | 
        
        
            | 
            | 
           1907 | 
               /**
  | 
        
        
            | 
            | 
           1908 | 
                * Helper used by {@link a_new_page_should_have_loaded_since_i_started_watching}
  | 
        
        
            | 
            | 
           1909 | 
                * and {@link a_new_page_should_not_have_loaded_since_i_started_watching}
  | 
        
        
            | 
            | 
           1910 | 
                * @return string xpath expression.
  | 
        
        
            | 
            | 
           1911 | 
                */
  | 
        
        
            | 
            | 
           1912 | 
               protected function get_page_load_xpath() {
  | 
        
        
            | 
            | 
           1913 | 
                   return "//span[@data-rel = '" . self::PAGE_LOAD_DETECTION_STRING . "']";
  | 
        
        
            | 
            | 
           1914 | 
               }
  | 
        
        
            | 
            | 
           1915 | 
              | 
        
        
            | 
            | 
           1916 | 
               /**
  | 
        
        
            | 
            | 
           1917 | 
                * Wait unit user press Enter/Return key. Useful when debugging a scenario.
  | 
        
        
            | 
            | 
           1918 | 
                *
  | 
        
        
            | 
            | 
           1919 | 
                * @Then /^(?:|I )pause(?:| scenario execution)$/
  | 
        
        
            | 
            | 
           1920 | 
                */
  | 
        
        
            | 
            | 
           1921 | 
               public function i_pause_scenario_execution() {
  | 
        
        
            | 
            | 
           1922 | 
                   $message = "<colour:lightYellow>Paused. Press <colour:lightRed>Enter/Return<colour:lightYellow> to continue.";
  | 
        
        
            | 
            | 
           1923 | 
                   behat_util::pause($this->getSession(), $message);
  | 
        
        
            | 
            | 
           1924 | 
               }
  | 
        
        
            | 
            | 
           1925 | 
              | 
        
        
            | 
            | 
           1926 | 
               /**
  | 
        
        
            | 
            | 
           1927 | 
                * Presses a given button in the browser.
  | 
        
        
            | 
            | 
           1928 | 
                * NOTE: Phantomjs and browserkit driver reloads page while navigating back and forward.
  | 
        
        
            | 
            | 
           1929 | 
                *
  | 
        
        
            | 
            | 
           1930 | 
                * @Then /^I press the "(back|forward|reload)" button in the browser$/
  | 
        
        
            | 
            | 
           1931 | 
                * @param string $button the button to press.
  | 
        
        
            | 
            | 
           1932 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           1933 | 
                */
  | 
        
        
            | 
            | 
           1934 | 
               public function i_press_in_the_browser($button) {
  | 
        
        
            | 
            | 
           1935 | 
                   $session = $this->getSession();
  | 
        
        
            | 
            | 
           1936 | 
              | 
        
        
            | 
            | 
           1937 | 
                   if ($button == 'back') {
  | 
        
        
            | 
            | 
           1938 | 
                       $session->back();
  | 
        
        
            | 
            | 
           1939 | 
                   } else if ($button == 'forward') {
  | 
        
        
            | 
            | 
           1940 | 
                       $session->forward();
  | 
        
        
            | 
            | 
           1941 | 
                   } else if ($button == 'reload') {
  | 
        
        
            | 
            | 
           1942 | 
                       $session->reload();
  | 
        
        
            | 
            | 
           1943 | 
                   } else {
  | 
        
        
            | 
            | 
           1944 | 
                       throw new ExpectationException('Unknown browser button.', $session);
  | 
        
        
            | 
            | 
           1945 | 
                   }
  | 
        
        
            | 
            | 
           1946 | 
               }
  | 
        
        
            | 
            | 
           1947 | 
              | 
        
        
            | 
            | 
           1948 | 
               /**
  | 
        
        
            | 
            | 
           1949 | 
                * Send key presses to the browser without first changing focusing, or applying the key presses to a specific
  | 
        
        
            | 
            | 
           1950 | 
                * element.
  | 
        
        
            | 
            | 
           1951 | 
                *
  | 
        
        
            | 
            | 
           1952 | 
                * Example usage of this step:
  | 
        
        
            | 
            | 
           1953 | 
                *     When I type "Penguin"
  | 
        
        
            | 
            | 
           1954 | 
                *
  | 
        
        
            | 
            | 
           1955 | 
                * @When    I type :keys
  | 
        
        
            | 
            | 
           1956 | 
                * @param   string $keys The key, or list of keys, to type
  | 
        
        
            | 
            | 
           1957 | 
                */
  | 
        
        
            | 
            | 
           1958 | 
               public function i_type(string $keys): void {
  | 
        
        
            | 
            | 
           1959 | 
                   // Certain keys, such as the newline character, must be converted to the appropriate character code.
  | 
        
        
            | 
            | 
           1960 | 
                   // Without this, keys will behave differently depending on the browser.
  | 
        
        
            | 
            | 
           1961 | 
                   $keylist = array_map(function($key): string {
  | 
        
        
            | 
            | 
           1962 | 
                       switch ($key) {
  | 
        
        
            | 
            | 
           1963 | 
                           case "\n":
  | 
        
        
            | 
            | 
           1964 | 
                               return behat_keys::ENTER;
  | 
        
        
            | 
            | 
           1965 | 
                           default:
  | 
        
        
            | 
            | 
           1966 | 
                               return $key;
  | 
        
        
            | 
            | 
           1967 | 
                       }
  | 
        
        
            | 
            | 
           1968 | 
                   }, str_split($keys));
  | 
        
        
            | 
            | 
           1969 | 
                   behat_base::type_keys($this->getSession(), $keylist);
  | 
        
        
            | 
            | 
           1970 | 
               }
  | 
        
        
            | 
            | 
           1971 | 
              | 
        
        
            | 
            | 
           1972 | 
               /**
  | 
        
        
            | 
            | 
           1973 | 
                * Press a named or character key with an optional set of modifiers.
  | 
        
        
            | 
            | 
           1974 | 
                *
  | 
        
        
            | 
            | 
           1975 | 
                * Supported named keys are:
  | 
        
        
            | 
            | 
           1976 | 
                * - up
  | 
        
        
            | 
            | 
           1977 | 
                * - down
  | 
        
        
            | 
            | 
           1978 | 
                * - left
  | 
        
        
            | 
            | 
           1979 | 
                * - right
  | 
        
        
            | 
            | 
           1980 | 
                * - pageup|page_up
  | 
        
        
            | 
            | 
           1981 | 
                * - pagedown|page_down
  | 
        
        
            | 
            | 
           1982 | 
                * - home
  | 
        
        
            | 
            | 
           1983 | 
                * - end
  | 
        
        
            | 
            | 
           1984 | 
                * - insert
  | 
        
        
            | 
            | 
           1985 | 
                * - delete
  | 
        
        
            | 
            | 
           1986 | 
                * - backspace
  | 
        
        
            | 
            | 
           1987 | 
                * - escape
  | 
        
        
            | 
            | 
           1988 | 
                * - enter
  | 
        
        
            | 
            | 
           1989 | 
                * - tab
  | 
        
        
            | 
            | 
           1990 | 
                *
  | 
        
        
            | 
            | 
           1991 | 
                * You can also use a single character for the key name e.g. 'Ctrl C'.
  | 
        
        
            | 
            | 
           1992 | 
                *
  | 
        
        
            | 
            | 
           1993 | 
                * Supported moderators are:
  | 
        
        
            | 
            | 
           1994 | 
                * - shift
  | 
        
        
            | 
            | 
           1995 | 
                * - ctrl
  | 
        
        
            | 
            | 
           1996 | 
                * - alt
  | 
        
        
            | 
            | 
           1997 | 
                * - meta
  | 
        
        
            | 
            | 
           1998 | 
                *
  | 
        
        
            | 
            | 
           1999 | 
                * Example usage of this new step:
  | 
        
        
            | 
            | 
           2000 | 
                *     When I press the up key
  | 
        
        
            | 
            | 
           2001 | 
                *     When I press the space key
  | 
        
        
            | 
            | 
           2002 | 
                *     When I press the shift tab key
  | 
        
        
            | 
            | 
           2003 | 
                *
  | 
        
        
            | 
            | 
           2004 | 
                * Multiple moderator keys can be combined using the '+' operator, for example:
  | 
        
        
            | 
            | 
           2005 | 
                *     When I press the ctrl+shift enter key
  | 
        
        
            | 
            | 
           2006 | 
                *     When I press the ctrl + shift enter key
  | 
        
        
            | 
            | 
           2007 | 
                *
  | 
        
        
            | 
            | 
           2008 | 
                * @When    /^I press the (?P<modifiers_string>.* )?(?P<key_string>.*) key$/
  | 
        
        
            | 
            | 
           2009 | 
                * @param   string $modifiers A list of keyboard modifiers, separated by the `+` character
  | 
        
        
            | 
            | 
           2010 | 
                * @param   string $key The name of the key to press
  | 
        
        
            | 
            | 
           2011 | 
                */
  | 
        
        
            | 
            | 
           2012 | 
               public function i_press_named_key(string $modifiers, string $key): void {
  | 
        
        
            | 
            | 
           2013 | 
                   behat_base::require_javascript_in_session($this->getSession());
  | 
        
        
            | 
            | 
           2014 | 
              | 
        
        
            | 
            | 
           2015 | 
                   $keys = [];
  | 
        
        
            | 
            | 
           2016 | 
              | 
        
        
            | 
            | 
           2017 | 
                   foreach (explode('+', $modifiers) as $modifier) {
  | 
        
        
            | 
            | 
           2018 | 
                       switch (strtoupper(trim($modifier))) {
  | 
        
        
            | 
            | 
           2019 | 
                           case '':
  | 
        
        
            | 
            | 
           2020 | 
                               break;
  | 
        
        
            | 
            | 
           2021 | 
                           case 'SHIFT':
  | 
        
        
            | 
            | 
           2022 | 
                               $keys[] = behat_keys::SHIFT;
  | 
        
        
            | 
            | 
           2023 | 
                               break;
  | 
        
        
            | 
            | 
           2024 | 
                           case 'CTRL':
  | 
        
        
            | 
            | 
           2025 | 
                               $keys[] = behat_keys::CONTROL;
  | 
        
        
            | 
            | 
           2026 | 
                               break;
  | 
        
        
            | 
            | 
           2027 | 
                           case 'ALT':
  | 
        
        
            | 
            | 
           2028 | 
                               $keys[] = behat_keys::ALT;
  | 
        
        
            | 
            | 
           2029 | 
                               break;
  | 
        
        
            | 
            | 
           2030 | 
                           case 'META':
  | 
        
        
            | 
            | 
           2031 | 
                               $keys[] = behat_keys::META;
  | 
        
        
            | 
            | 
           2032 | 
                               break;
  | 
        
        
            | 
            | 
           2033 | 
                           default:
  | 
        
        
            | 
            | 
           2034 | 
                               throw new \coding_exception("Unknown modifier key '$modifier'}");
  | 
        
        
            | 
            | 
           2035 | 
                       }
  | 
        
        
            | 
            | 
           2036 | 
                   }
  | 
        
        
            | 
            | 
           2037 | 
              | 
        
        
            | 
            | 
           2038 | 
                   $modifier = trim($key);
  | 
        
        
            | 
            | 
           2039 | 
                   switch (strtoupper($key)) {
  | 
        
        
            | 
            | 
           2040 | 
                       case 'UP':
  | 
        
        
            | 
            | 
           2041 | 
                           $keys[] = behat_keys::ARROW_UP;
  | 
        
        
            | 
            | 
           2042 | 
                           break;
  | 
        
        
            | 
            | 
           2043 | 
                       case 'DOWN':
  | 
        
        
            | 
            | 
           2044 | 
                           $keys[] = behat_keys::ARROW_DOWN;
  | 
        
        
            | 
            | 
           2045 | 
                           break;
  | 
        
        
            | 
            | 
           2046 | 
                       case 'LEFT':
  | 
        
        
            | 
            | 
           2047 | 
                           $keys[] = behat_keys::ARROW_LEFT;
  | 
        
        
            | 
            | 
           2048 | 
                           break;
  | 
        
        
            | 
            | 
           2049 | 
                       case 'RIGHT':
  | 
        
        
            | 
            | 
           2050 | 
                           $keys[] = behat_keys::ARROW_RIGHT;
  | 
        
        
            | 
            | 
           2051 | 
                           break;
  | 
        
        
            | 
            | 
           2052 | 
                       case 'HOME':
  | 
        
        
            | 
            | 
           2053 | 
                           $keys[] = behat_keys::HOME;
  | 
        
        
            | 
            | 
           2054 | 
                           break;
  | 
        
        
            | 
            | 
           2055 | 
                       case 'END':
  | 
        
        
            | 
            | 
           2056 | 
                           $keys[] = behat_keys::END;
  | 
        
        
            | 
            | 
           2057 | 
                           break;
  | 
        
        
            | 
            | 
           2058 | 
                       case 'INSERT':
  | 
        
        
            | 
            | 
           2059 | 
                           $keys[] = behat_keys::INSERT;
  | 
        
        
            | 
            | 
           2060 | 
                           break;
  | 
        
        
            | 
            | 
           2061 | 
                       case 'BACKSPACE':
  | 
        
        
            | 
            | 
           2062 | 
                           $keys[] = behat_keys::BACKSPACE;
  | 
        
        
            | 
            | 
           2063 | 
                           break;
  | 
        
        
            | 
            | 
           2064 | 
                       case 'DELETE':
  | 
        
        
            | 
            | 
           2065 | 
                           $keys[] = behat_keys::DELETE;
  | 
        
        
            | 
            | 
           2066 | 
                           break;
  | 
        
        
            | 
            | 
           2067 | 
                       case 'PAGEUP':
  | 
        
        
            | 
            | 
           2068 | 
                       case 'PAGE_UP':
  | 
        
        
            | 
            | 
           2069 | 
                           $keys[] = behat_keys::PAGE_UP;
  | 
        
        
            | 
            | 
           2070 | 
                           break;
  | 
        
        
            | 
            | 
           2071 | 
                       case 'PAGEDOWN':
  | 
        
        
            | 
            | 
           2072 | 
                       case 'PAGE_DOWN':
  | 
        
        
            | 
            | 
           2073 | 
                           $keys[] = behat_keys::PAGE_DOWN;
  | 
        
        
            | 
            | 
           2074 | 
                           break;
  | 
        
        
            | 
            | 
           2075 | 
                       case 'ESCAPE':
  | 
        
        
            | 
            | 
           2076 | 
                           $keys[] = behat_keys::ESCAPE;
  | 
        
        
            | 
            | 
           2077 | 
                           break;
  | 
        
        
            | 
            | 
           2078 | 
                       case 'ENTER':
  | 
        
        
            | 
            | 
           2079 | 
                           $keys[] = behat_keys::ENTER;
  | 
        
        
            | 
            | 
           2080 | 
                           break;
  | 
        
        
            | 
            | 
           2081 | 
                       case 'TAB':
  | 
        
        
            | 
            | 
           2082 | 
                           $keys[] = behat_keys::TAB;
  | 
        
        
            | 
            | 
           2083 | 
                           break;
  | 
        
        
            | 
            | 
           2084 | 
                       case 'SPACE':
  | 
        
        
            | 
            | 
           2085 | 
                           $keys[] = behat_keys::SPACE;
  | 
        
        
            | 
            | 
           2086 | 
                           break;
  | 
        
        
            | 
            | 
           2087 | 
                       case 'MULTIPLY':
  | 
        
        
            | 
            | 
           2088 | 
                           $keys[] = behat_keys::MULTIPLY;
  | 
        
        
            | 
            | 
           2089 | 
                           break;
  | 
        
        
            | 
            | 
           2090 | 
                       default:
  | 
        
        
            | 
            | 
           2091 | 
                           // You can enter a single ASCII character (e.g. a letter) to directly type that key.
  | 
        
        
            | 
            | 
           2092 | 
                           if (strlen($key) === 1) {
  | 
        
        
            | 
            | 
           2093 | 
                               $keys[] = strtolower($key);
  | 
        
        
            | 
            | 
           2094 | 
                           } else {
  | 
        
        
            | 
            | 
           2095 | 
                               throw new \coding_exception("Unknown key '$key'}");
  | 
        
        
            | 
            | 
           2096 | 
                           }
  | 
        
        
            | 
            | 
           2097 | 
                   }
  | 
        
        
            | 
            | 
           2098 | 
              | 
        
        
            | 
            | 
           2099 | 
                   behat_base::type_keys($this->getSession(), $keys);
  | 
        
        
            | 
            | 
           2100 | 
               }
  | 
        
        
            | 
            | 
           2101 | 
              | 
        
        
            | 
            | 
           2102 | 
               /**
  | 
        
        
            | 
            | 
           2103 | 
                * Trigger a keydown event for a key on a specific element.
  | 
        
        
            | 
            | 
           2104 | 
                *
  | 
        
        
            | 
            | 
           2105 | 
                * @When /^I press key "(?P<key_string>(?:[^"]|\\")*)" in "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           2106 | 
                * @param string $key either char-code or character itself,
  | 
        
        
            | 
            | 
           2107 | 
                *               may optionally be prefixed with ctrl-, alt-, shift- or meta-
  | 
        
        
            | 
            | 
           2108 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           2109 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           2110 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           2111 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           2112 | 
                */
  | 
        
        
            | 
            | 
           2113 | 
               public function i_press_key_in_element($key, $element, $selectortype) {
  | 
        
        
            | 
            | 
           2114 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           2115 | 
                       throw new DriverException('Key down step is not available with Javascript disabled');
  | 
        
        
            | 
            | 
           2116 | 
                   }
  | 
        
        
            | 
            | 
           2117 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
            | 
            | 
           2118 | 
                   $node = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           2119 | 
                   $modifier = null;
  | 
        
        
            | 
            | 
           2120 | 
                   $validmodifiers = array('ctrl', 'alt', 'shift', 'meta');
  | 
        
        
            | 
            | 
           2121 | 
                   $char = $key;
  | 
        
        
            | 
            | 
           2122 | 
                   if (strpos($key, '-')) {
  | 
        
        
           | 1441 | 
           ariadna | 
           2123 | 
                       [$modifier, $char] = preg_split('/-/', $key, 2);
  | 
        
        
           | 1 | 
           efrain | 
           2124 | 
                       $modifier = strtolower($modifier);
  | 
        
        
            | 
            | 
           2125 | 
                       if (!in_array($modifier, $validmodifiers)) {
  | 
        
        
            | 
            | 
           2126 | 
                           throw new ExpectationException(sprintf('Unknown key modifier: %s.', $modifier),
  | 
        
        
            | 
            | 
           2127 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           2128 | 
                       }
  | 
        
        
            | 
            | 
           2129 | 
                   }
  | 
        
        
            | 
            | 
           2130 | 
                   if (is_numeric($char)) {
  | 
        
        
            | 
            | 
           2131 | 
                       $char = (int)$char;
  | 
        
        
            | 
            | 
           2132 | 
                   }
  | 
        
        
            | 
            | 
           2133 | 
              | 
        
        
            | 
            | 
           2134 | 
                   $node->keyDown($char, $modifier);
  | 
        
        
            | 
            | 
           2135 | 
                   $node->keyPress($char, $modifier);
  | 
        
        
            | 
            | 
           2136 | 
                   $node->keyUp($char, $modifier);
  | 
        
        
            | 
            | 
           2137 | 
               }
  | 
        
        
            | 
            | 
           2138 | 
              | 
        
        
            | 
            | 
           2139 | 
               /**
  | 
        
        
            | 
            | 
           2140 | 
                * Press tab key on a specific element.
  | 
        
        
            | 
            | 
           2141 | 
                *
  | 
        
        
            | 
            | 
           2142 | 
                * @When /^I press tab key in "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           2143 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           2144 | 
                * @param string $selectortype The type of what we look for
  | 
        
        
            | 
            | 
           2145 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           2146 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           2147 | 
                */
  | 
        
        
            | 
            | 
           2148 | 
               public function i_post_tab_key_in_element($element, $selectortype) {
  | 
        
        
            | 
            | 
           2149 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           2150 | 
                       throw new DriverException('Tab press step is not available with Javascript disabled');
  | 
        
        
            | 
            | 
           2151 | 
                   }
  | 
        
        
            | 
            | 
           2152 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
            | 
            | 
           2153 | 
                   $node = $this->get_selected_node($selectortype, $element);
  | 
        
        
           | 1441 | 
           ariadna | 
           2154 | 
                   $this->execute([self::class, 'i_click_on'], [$node, 'NodeElement']);
  | 
        
        
            | 
            | 
           2155 | 
                   $this->execute([self::class, 'i_press_named_key'], ['', 'tab']);
  | 
        
        
           | 1 | 
           efrain | 
           2156 | 
               }
  | 
        
        
            | 
            | 
           2157 | 
              | 
        
        
            | 
            | 
           2158 | 
               /**
  | 
        
        
           | 1441 | 
           ariadna | 
           2159 | 
                * Checks if database family used is using one of the specified, else skip. (mysql, postgres, mssql, etc.)
  | 
        
        
           | 1 | 
           efrain | 
           2160 | 
                *
  | 
        
        
            | 
            | 
           2161 | 
                * @Given /^database family used is one of the following:$/
  | 
        
        
            | 
            | 
           2162 | 
                * @param TableNode $databasefamilies list of database.
  | 
        
        
            | 
            | 
           2163 | 
                * @return void.
  | 
        
        
            | 
            | 
           2164 | 
                * @throws \Moodle\BehatExtension\Exception\SkippedException
  | 
        
        
            | 
            | 
           2165 | 
                */
  | 
        
        
            | 
            | 
           2166 | 
               public function database_family_used_is_one_of_the_following(TableNode $databasefamilies) {
  | 
        
        
            | 
            | 
           2167 | 
                   global $DB;
  | 
        
        
            | 
            | 
           2168 | 
              | 
        
        
            | 
            | 
           2169 | 
                   $dbfamily = $DB->get_dbfamily();
  | 
        
        
            | 
            | 
           2170 | 
              | 
        
        
            | 
            | 
           2171 | 
                   // Check if used db family is one of the specified ones. If yes then return.
  | 
        
        
            | 
            | 
           2172 | 
                   foreach ($databasefamilies->getRows() as $dbfamilytocheck) {
  | 
        
        
            | 
            | 
           2173 | 
                       if ($dbfamilytocheck[0] == $dbfamily) {
  | 
        
        
            | 
            | 
           2174 | 
                           return;
  | 
        
        
            | 
            | 
           2175 | 
                       }
  | 
        
        
            | 
            | 
           2176 | 
                   }
  | 
        
        
            | 
            | 
           2177 | 
              | 
        
        
            | 
            | 
           2178 | 
                   throw new \Moodle\BehatExtension\Exception\SkippedException();
  | 
        
        
            | 
            | 
           2179 | 
               }
  | 
        
        
            | 
            | 
           2180 | 
              | 
        
        
            | 
            | 
           2181 | 
               /**
  | 
        
        
            | 
            | 
           2182 | 
                * Checks if given plugin is installed, and skips the current scenario if not.
  | 
        
        
            | 
            | 
           2183 | 
                *
  | 
        
        
            | 
            | 
           2184 | 
                * @Given the :plugin plugin is installed
  | 
        
        
            | 
            | 
           2185 | 
                * @param string $plugin frankenstyle plugin name, e.g. 'filter_embedquestion'.
  | 
        
        
            | 
            | 
           2186 | 
                * @throws \Moodle\BehatExtension\Exception\SkippedException
  | 
        
        
            | 
            | 
           2187 | 
                */
  | 
        
        
            | 
            | 
           2188 | 
               public function plugin_is_installed(string $plugin): void {
  | 
        
        
            | 
            | 
           2189 | 
                   $path = core_component::get_component_directory($plugin);
  | 
        
        
            | 
            | 
           2190 | 
                   if (!is_readable($path . '/version.php')) {
  | 
        
        
            | 
            | 
           2191 | 
                       throw new \Moodle\BehatExtension\Exception\SkippedException(
  | 
        
        
            | 
            | 
           2192 | 
                               'Skipping this scenario because the ' . $plugin . ' is not installed.');
  | 
        
        
            | 
            | 
           2193 | 
                   }
  | 
        
        
            | 
            | 
           2194 | 
               }
  | 
        
        
            | 
            | 
           2195 | 
              | 
        
        
            | 
            | 
           2196 | 
               /**
  | 
        
        
            | 
            | 
           2197 | 
                * Checks focus is with the given element.
  | 
        
        
            | 
            | 
           2198 | 
                *
  | 
        
        
            | 
            | 
           2199 | 
                * @Then /^the focused element is( not)? "(?P<node_string>(?:[^"]|\\")*)" "(?P<node_selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           2200 | 
                * @param string $not optional step verifier
  | 
        
        
            | 
            | 
           2201 | 
                * @param string $nodeelement Element identifier
  | 
        
        
            | 
            | 
           2202 | 
                * @param string $nodeselectortype Element type
  | 
        
        
            | 
            | 
           2203 | 
                * @throws DriverException If not using JavaScript
  | 
        
        
            | 
            | 
           2204 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           2205 | 
                */
  | 
        
        
            | 
            | 
           2206 | 
               public function the_focused_element_is($not, $nodeelement, $nodeselectortype) {
  | 
        
        
            | 
            | 
           2207 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           2208 | 
                       throw new DriverException('Checking focus on an element requires JavaScript');
  | 
        
        
            | 
            | 
           2209 | 
                   }
  | 
        
        
            | 
            | 
           2210 | 
              | 
        
        
            | 
            | 
           2211 | 
                   $element = $this->find($nodeselectortype, $nodeelement);
  | 
        
        
            | 
            | 
           2212 | 
                   $xpath = addslashes_js($element->getXpath());
  | 
        
        
            | 
            | 
           2213 | 
                   $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '",
  | 
        
        
            | 
            | 
           2214 | 
                           document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';
  | 
        
        
            | 
            | 
           2215 | 
                   $targetisfocused = $this->evaluate_script($script);
  | 
        
        
            | 
            | 
           2216 | 
                   if ($not == ' not') {
  | 
        
        
            | 
            | 
           2217 | 
                       if ($targetisfocused) {
  | 
        
        
            | 
            | 
           2218 | 
                           throw new ExpectationException("$nodeelement $nodeselectortype is focused", $this->getSession());
  | 
        
        
            | 
            | 
           2219 | 
                       }
  | 
        
        
            | 
            | 
           2220 | 
                   } else {
  | 
        
        
            | 
            | 
           2221 | 
                       if (!$targetisfocused) {
  | 
        
        
            | 
            | 
           2222 | 
                           throw new ExpectationException("$nodeelement $nodeselectortype is not focused", $this->getSession());
  | 
        
        
            | 
            | 
           2223 | 
                       }
  | 
        
        
            | 
            | 
           2224 | 
                   }
  | 
        
        
            | 
            | 
           2225 | 
               }
  | 
        
        
            | 
            | 
           2226 | 
              | 
        
        
            | 
            | 
           2227 | 
               /**
  | 
        
        
            | 
            | 
           2228 | 
                * Checks focus is with the given element.
  | 
        
        
            | 
            | 
           2229 | 
                *
  | 
        
        
            | 
            | 
           2230 | 
                * @Then /^the focused element is( not)? "(?P<n>(?:[^"]|\\")*)" "(?P<ns>[^"]*)" in the "(?P<c>(?:[^"]|\\")*)" "(?P<cs>[^"]*)"$/
  | 
        
        
            | 
            | 
           2231 | 
                * @param string $not string optional step verifier
  | 
        
        
            | 
            | 
           2232 | 
                * @param string $element Element identifier
  | 
        
        
            | 
            | 
           2233 | 
                * @param string $selectortype Element type
  | 
        
        
            | 
            | 
           2234 | 
                * @param string $nodeelement Element we look in
  | 
        
        
            | 
            | 
           2235 | 
                * @param string $nodeselectortype The type of selector where we look in
  | 
        
        
            | 
            | 
           2236 | 
                * @throws DriverException If not using JavaScript
  | 
        
        
            | 
            | 
           2237 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           2238 | 
                */
  | 
        
        
            | 
            | 
           2239 | 
               public function the_focused_element_is_in_the($not, $element, $selectortype, $nodeelement, $nodeselectortype) {
  | 
        
        
            | 
            | 
           2240 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           2241 | 
                       throw new DriverException('Checking focus on an element requires JavaScript');
  | 
        
        
            | 
            | 
           2242 | 
                   }
  | 
        
        
            | 
            | 
           2243 | 
                   $element = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
  | 
        
        
            | 
            | 
           2244 | 
                   $xpath = addslashes_js($element->getXpath());
  | 
        
        
            | 
            | 
           2245 | 
                   $script = 'return (function() { return document.activeElement === document.evaluate("' . $xpath . '",
  | 
        
        
            | 
            | 
           2246 | 
                           document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; })(); ';
  | 
        
        
            | 
            | 
           2247 | 
                   $targetisfocused = $this->evaluate_script($script);
  | 
        
        
            | 
            | 
           2248 | 
                   if ($not == ' not') {
  | 
        
        
            | 
            | 
           2249 | 
                       if ($targetisfocused) {
  | 
        
        
            | 
            | 
           2250 | 
                           throw new ExpectationException("$nodeelement $nodeselectortype is focused", $this->getSession());
  | 
        
        
            | 
            | 
           2251 | 
                       }
  | 
        
        
            | 
            | 
           2252 | 
                   } else {
  | 
        
        
            | 
            | 
           2253 | 
                       if (!$targetisfocused) {
  | 
        
        
            | 
            | 
           2254 | 
                           throw new ExpectationException("$nodeelement $nodeselectortype is not focused", $this->getSession());
  | 
        
        
            | 
            | 
           2255 | 
                       }
  | 
        
        
            | 
            | 
           2256 | 
                   }
  | 
        
        
            | 
            | 
           2257 | 
               }
  | 
        
        
            | 
            | 
           2258 | 
              | 
        
        
            | 
            | 
           2259 | 
               /**
  | 
        
        
            | 
            | 
           2260 | 
                * Manually press tab key.
  | 
        
        
            | 
            | 
           2261 | 
                *
  | 
        
        
            | 
            | 
           2262 | 
                * @When /^I press( shift)? tab$/
  | 
        
        
            | 
            | 
           2263 | 
                * @param string $shift string optional step verifier
  | 
        
        
            | 
            | 
           2264 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           2265 | 
                */
  | 
        
        
            | 
            | 
           2266 | 
               public function i_manually_press_tab($shift = '') {
  | 
        
        
            | 
            | 
           2267 | 
                   if (empty($shift)) {
  | 
        
        
           | 1441 | 
           ariadna | 
           2268 | 
                       $this->execute([self::class, 'i_press_named_key'], ['', 'tab']);
  | 
        
        
           | 1 | 
           efrain | 
           2269 | 
                   } else {
  | 
        
        
           | 1441 | 
           ariadna | 
           2270 | 
                       $this->execute([self::class, 'i_press_named_key'], ['shift', 'tab']);
  | 
        
        
           | 1 | 
           efrain | 
           2271 | 
                   }
  | 
        
        
            | 
            | 
           2272 | 
               }
  | 
        
        
            | 
            | 
           2273 | 
              | 
        
        
            | 
            | 
           2274 | 
               /**
  | 
        
        
            | 
            | 
           2275 | 
                * Trigger click on node via javascript instead of actually clicking on it via pointer.
  | 
        
        
            | 
            | 
           2276 | 
                * This function resolves the issue of nested elements.
  | 
        
        
            | 
            | 
           2277 | 
                *
  | 
        
        
            | 
            | 
           2278 | 
                * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" skipping visibility check$/
  | 
        
        
            | 
            | 
           2279 | 
                * @param string $element
  | 
        
        
            | 
            | 
           2280 | 
                * @param string $selectortype
  | 
        
        
            | 
            | 
           2281 | 
                */
  | 
        
        
            | 
            | 
           2282 | 
               public function i_click_on_skipping_visibility_check($element, $selectortype) {
  | 
        
        
            | 
            | 
           2283 | 
              | 
        
        
            | 
            | 
           2284 | 
                   // Gets the node based on the requested selector type and locator.
  | 
        
        
            | 
            | 
           2285 | 
                   $node = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           2286 | 
                   $this->js_trigger_click($node);
  | 
        
        
            | 
            | 
           2287 | 
               }
  | 
        
        
            | 
            | 
           2288 | 
              | 
        
        
            | 
            | 
           2289 | 
               /**
  | 
        
        
            | 
            | 
           2290 | 
                * Checks, that the specified element contains the specified text a certain amount of times.
  | 
        
        
            | 
            | 
           2291 | 
                * When running Javascript tests it also considers that texts may be hidden.
  | 
        
        
            | 
            | 
           2292 | 
                *
  | 
        
        
            | 
            | 
           2293 | 
                * @Then /^I should see "(?P<elementscount_number>\d+)" occurrences of "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           2294 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           2295 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           2296 | 
                * @param int    $elementscount How many occurrences of the element we look for.
  | 
        
        
            | 
            | 
           2297 | 
                * @param string $text
  | 
        
        
            | 
            | 
           2298 | 
                * @param string $element Element we look in.
  | 
        
        
            | 
            | 
           2299 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           2300 | 
                */
  | 
        
        
            | 
            | 
           2301 | 
               public function i_should_see_occurrences_of_in_element($elementscount, $text, $element, $selectortype) {
  | 
        
        
            | 
            | 
           2302 | 
              | 
        
        
            | 
            | 
           2303 | 
                   // Getting the container where the text should be found.
  | 
        
        
            | 
            | 
           2304 | 
                   $container = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           2305 | 
              | 
        
        
            | 
            | 
           2306 | 
                   // Looking for all the matching nodes without any other descendant matching the
  | 
        
        
            | 
            | 
           2307 | 
                   // same xpath (we are using contains(., ....).
  | 
        
        
            | 
            | 
           2308 | 
                   $xpathliteral = behat_context_helper::escape($text);
  | 
        
        
            | 
            | 
           2309 | 
                   $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" .
  | 
        
        
            | 
            | 
           2310 | 
                           "[count(descendant::*[contains(., $xpathliteral)]) = 0]";
  | 
        
        
            | 
            | 
           2311 | 
              | 
        
        
            | 
            | 
           2312 | 
                   $nodes = $this->find_all('xpath', $xpath, false, $container);
  | 
        
        
            | 
            | 
           2313 | 
              | 
        
        
            | 
            | 
           2314 | 
                   if ($this->running_javascript()) {
  | 
        
        
            | 
            | 
           2315 | 
                       $nodes = array_filter($nodes, function($node) {
  | 
        
        
            | 
            | 
           2316 | 
                           return $node->isVisible();
  | 
        
        
            | 
            | 
           2317 | 
                       });
  | 
        
        
            | 
            | 
           2318 | 
                   }
  | 
        
        
            | 
            | 
           2319 | 
              | 
        
        
            | 
            | 
           2320 | 
                   if ($elementscount != count($nodes)) {
  | 
        
        
            | 
            | 
           2321 | 
                       throw new ExpectationException('Found '.count($nodes).' elements in column. Expected '.$elementscount,
  | 
        
        
            | 
            | 
           2322 | 
                               $this->getSession());
  | 
        
        
            | 
            | 
           2323 | 
                   }
  | 
        
        
            | 
            | 
           2324 | 
               }
  | 
        
        
            | 
            | 
           2325 | 
              | 
        
        
            | 
            | 
           2326 | 
               /**
  | 
        
        
            | 
            | 
           2327 | 
                * Checks, that the specified element contains the specified node type a certain amount of times.
  | 
        
        
            | 
            | 
           2328 | 
                * When running Javascript tests it also considers that texts may be hidden.
  | 
        
        
            | 
            | 
           2329 | 
                *
  | 
        
        
            | 
            | 
           2330 | 
                * @Then /^I should see "(?P<elementscount_number>\d+)" node occurrences of type "(?P<node_type>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/
  | 
        
        
            | 
            | 
           2331 | 
                * @throws ElementNotFoundException
  | 
        
        
            | 
            | 
           2332 | 
                * @throws ExpectationException
  | 
        
        
            | 
            | 
           2333 | 
                * @param int    $elementscount How many occurrences of the element we look for.
  | 
        
        
            | 
            | 
           2334 | 
                * @param string $nodetype
  | 
        
        
            | 
            | 
           2335 | 
                * @param string $element Element we look in.
  | 
        
        
            | 
            | 
           2336 | 
                * @param string $selectortype The type of element where we are looking in.
  | 
        
        
            | 
            | 
           2337 | 
                */
  | 
        
        
            | 
            | 
           2338 | 
               public function i_should_see_node_occurrences_of_type_in_element(int $elementscount, string $nodetype, string $element, string $selectortype) {
  | 
        
        
            | 
            | 
           2339 | 
              | 
        
        
            | 
            | 
           2340 | 
                   // Getting the container where the text should be found.
  | 
        
        
            | 
            | 
           2341 | 
                   $container = $this->get_selected_node($selectortype, $element);
  | 
        
        
            | 
            | 
           2342 | 
              | 
        
        
            | 
            | 
           2343 | 
                   $xpath = "/descendant-or-self::$nodetype [count(descendant::$nodetype) = 0]";
  | 
        
        
            | 
            | 
           2344 | 
              | 
        
        
            | 
            | 
           2345 | 
                   $nodes = $this->find_all('xpath', $xpath, false, $container);
  | 
        
        
            | 
            | 
           2346 | 
              | 
        
        
            | 
            | 
           2347 | 
                   if ($this->running_javascript()) {
  | 
        
        
            | 
            | 
           2348 | 
                       $nodes = array_filter($nodes, function($node) {
  | 
        
        
            | 
            | 
           2349 | 
                           return $node->isVisible();
  | 
        
        
            | 
            | 
           2350 | 
                       });
  | 
        
        
            | 
            | 
           2351 | 
                   }
  | 
        
        
            | 
            | 
           2352 | 
              | 
        
        
            | 
            | 
           2353 | 
                   if ($elementscount != count($nodes)) {
  | 
        
        
            | 
            | 
           2354 | 
                       throw new ExpectationException('Found '.count($nodes).' elements in column. Expected '.$elementscount,
  | 
        
        
            | 
            | 
           2355 | 
                           $this->getSession());
  | 
        
        
            | 
            | 
           2356 | 
                   }
  | 
        
        
            | 
            | 
           2357 | 
               }
  | 
        
        
            | 
            | 
           2358 | 
              | 
        
        
            | 
            | 
           2359 | 
               /**
  | 
        
        
            | 
            | 
           2360 | 
                * Manually press enter key.
  | 
        
        
            | 
            | 
           2361 | 
                *
  | 
        
        
            | 
            | 
           2362 | 
                * @When /^I press enter/
  | 
        
        
            | 
            | 
           2363 | 
                * @throws DriverException
  | 
        
        
            | 
            | 
           2364 | 
                */
  | 
        
        
            | 
            | 
           2365 | 
               public function i_manually_press_enter() {
  | 
        
        
           | 1441 | 
           ariadna | 
           2366 | 
                   $this->execute([self::class, 'i_press_named_key'], ['', 'enter']);
  | 
        
        
           | 1 | 
           efrain | 
           2367 | 
               }
  | 
        
        
            | 
            | 
           2368 | 
              | 
        
        
            | 
            | 
           2369 | 
               /**
  | 
        
        
            | 
            | 
           2370 | 
                * Visit a local URL relative to the behat root.
  | 
        
        
            | 
            | 
           2371 | 
                *
  | 
        
        
            | 
            | 
           2372 | 
                * @When I visit :localurl
  | 
        
        
            | 
            | 
           2373 | 
                *
  | 
        
        
            | 
            | 
           2374 | 
                * @param string|moodle_url $localurl The URL relative to the behat_wwwroot to visit.
  | 
        
        
            | 
            | 
           2375 | 
                */
  | 
        
        
            | 
            | 
           2376 | 
               public function i_visit($localurl): void {
  | 
        
        
            | 
            | 
           2377 | 
                   $localurl = new moodle_url($localurl);
  | 
        
        
            | 
            | 
           2378 | 
                   $this->getSession()->visit($this->locate_path($localurl->out_as_local_url(false)));
  | 
        
        
            | 
            | 
           2379 | 
               }
  | 
        
        
            | 
            | 
           2380 | 
              | 
        
        
            | 
            | 
           2381 | 
               /**
  | 
        
        
            | 
            | 
           2382 | 
                * Increase the webdriver timeouts.
  | 
        
        
            | 
            | 
           2383 | 
                *
  | 
        
        
            | 
            | 
           2384 | 
                * This should be reset between scenarios, or can be called again to decrease the timeouts.
  | 
        
        
            | 
            | 
           2385 | 
                *
  | 
        
        
            | 
            | 
           2386 | 
                * @Given I mark this test as slow setting a timeout factor of :factor
  | 
        
        
            | 
            | 
           2387 | 
                */
  | 
        
        
            | 
            | 
           2388 | 
               public function i_mark_this_test_as_long_running(int $factor = 2): void {
  | 
        
        
            | 
            | 
           2389 | 
                   $this->set_test_timeout_factor($factor);
  | 
        
        
            | 
            | 
           2390 | 
               }
  | 
        
        
            | 
            | 
           2391 | 
              | 
        
        
            | 
            | 
           2392 | 
               /**
  | 
        
        
            | 
            | 
           2393 | 
                * Click on a dynamic tab to load its content
  | 
        
        
            | 
            | 
           2394 | 
                *
  | 
        
        
            | 
            | 
           2395 | 
                * @Given /^I click on the "(?P<tab_string>(?:[^"]|\\")*)" dynamic tab$/
  | 
        
        
            | 
            | 
           2396 | 
                *
  | 
        
        
            | 
            | 
           2397 | 
                * @param string $tabname
  | 
        
        
            | 
            | 
           2398 | 
                */
  | 
        
        
            | 
            | 
           2399 | 
               public function i_click_on_the_dynamic_tab(string $tabname): void {
  | 
        
        
            | 
            | 
           2400 | 
                   $xpath = "//*[@id='dynamictabs-tabs'][descendant::a[contains(text(), '" . $this->escape($tabname) . "')]]";
  | 
        
        
           | 1441 | 
           ariadna | 
           2401 | 
                   $this->execute([self::class, 'i_click_on_in_the'],
  | 
        
        
           | 1 | 
           efrain | 
           2402 | 
                       [$tabname, 'link', $xpath, 'xpath_element']);
  | 
        
        
            | 
            | 
           2403 | 
               }
  | 
        
        
            | 
            | 
           2404 | 
              | 
        
        
            | 
            | 
           2405 | 
               /**
  | 
        
        
            | 
            | 
           2406 | 
                * Enable an specific plugin.
  | 
        
        
            | 
            | 
           2407 | 
                *
  | 
        
        
            | 
            | 
           2408 | 
                * @When /^I enable "(?P<plugin_string>(?:[^"]|\\")*)" "(?P<plugintype_string>[^"]*)" plugin$/
  | 
        
        
            | 
            | 
           2409 | 
                * @param string $plugin Plugin we look for
  | 
        
        
            | 
            | 
           2410 | 
                * @param string $plugintype The type of the plugin
  | 
        
        
            | 
            | 
           2411 | 
                */
  | 
        
        
           | 1441 | 
           ariadna | 
           2412 | 
               #[\core\attribute\example('I enable "subsection" "mod" plugin')]
  | 
        
        
           | 1 | 
           efrain | 
           2413 | 
               public function i_enable_plugin($plugin, $plugintype) {
  | 
        
        
            | 
            | 
           2414 | 
                   $class = core_plugin_manager::resolve_plugininfo_class($plugintype);
  | 
        
        
            | 
            | 
           2415 | 
                   $class::enable_plugin($plugin, true);
  | 
        
        
            | 
            | 
           2416 | 
               }
  | 
        
        
            | 
            | 
           2417 | 
              | 
        
        
            | 
            | 
           2418 | 
               /**
  | 
        
        
           | 1441 | 
           ariadna | 
           2419 | 
                * Disable an specific plugin.
  | 
        
        
            | 
            | 
           2420 | 
                *
  | 
        
        
            | 
            | 
           2421 | 
                * @When /^I disable "(?P<plugin_string>(?:[^"]|\\")*)" "(?P<plugintype_string>[^"]*)" plugin$/
  | 
        
        
            | 
            | 
           2422 | 
                * @param string $plugin Plugin we look for
  | 
        
        
            | 
            | 
           2423 | 
                * @param string $plugintype The type of the plugin
  | 
        
        
            | 
            | 
           2424 | 
                */
  | 
        
        
            | 
            | 
           2425 | 
               #[\core\attribute\example('I disable "page" "mod" plugin')]
  | 
        
        
            | 
            | 
           2426 | 
               public function i_disable_plugin($plugin, $plugintype) {
  | 
        
        
            | 
            | 
           2427 | 
                   $class = core_plugin_manager::resolve_plugininfo_class($plugintype);
  | 
        
        
            | 
            | 
           2428 | 
                   $class::enable_plugin($plugin, false);
  | 
        
        
            | 
            | 
           2429 | 
               }
  | 
        
        
            | 
            | 
           2430 | 
              | 
        
        
            | 
            | 
           2431 | 
               /**
  | 
        
        
           | 1 | 
           efrain | 
           2432 | 
                * Set the default text editor to the named text editor.
  | 
        
        
            | 
            | 
           2433 | 
                *
  | 
        
        
            | 
            | 
           2434 | 
                * @Given the default editor is set to :editor
  | 
        
        
            | 
            | 
           2435 | 
                * @param string $editor
  | 
        
        
            | 
            | 
           2436 | 
                * @throws ExpectationException If the specified editor is not available.
  | 
        
        
            | 
            | 
           2437 | 
                */
  | 
        
        
            | 
            | 
           2438 | 
               public function the_default_editor_is_set_to(string $editor): void {
  | 
        
        
            | 
            | 
           2439 | 
                   global $CFG;
  | 
        
        
            | 
            | 
           2440 | 
              | 
        
        
            | 
            | 
           2441 | 
                   // Check if the provided editor is available.
  | 
        
        
            | 
            | 
           2442 | 
                   if (!array_key_exists($editor, editors_get_available())) {
  | 
        
        
            | 
            | 
           2443 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           2444 | 
                           "Unable to set the editor to {$editor} as it is not installed. The available editors are: " .
  | 
        
        
            | 
            | 
           2445 | 
                               implode(', ', array_keys(editors_get_available())),
  | 
        
        
            | 
            | 
           2446 | 
                           $this->getSession()
  | 
        
        
            | 
            | 
           2447 | 
                       );
  | 
        
        
            | 
            | 
           2448 | 
                   }
  | 
        
        
            | 
            | 
           2449 | 
              | 
        
        
            | 
            | 
           2450 | 
                   // Make the provided editor the default one in $CFG->texteditors by
  | 
        
        
           | 1441 | 
           ariadna | 
           2451 | 
                   // moving it to the first [editor],tiny,textarea on the list.
  | 
        
        
           | 1 | 
           efrain | 
           2452 | 
                   $list = explode(',', $CFG->texteditors);
  | 
        
        
            | 
            | 
           2453 | 
                   array_unshift($list, $editor);
  | 
        
        
            | 
            | 
           2454 | 
                   $list = array_unique($list);
  | 
        
        
            | 
            | 
           2455 | 
              | 
        
        
            | 
            | 
           2456 | 
                   // Set the list new list of editors.
  | 
        
        
            | 
            | 
           2457 | 
                   set_config('texteditors', implode(',', $list));
  | 
        
        
            | 
            | 
           2458 | 
               }
  | 
        
        
            | 
            | 
           2459 | 
              | 
        
        
            | 
            | 
           2460 | 
               /**
  | 
        
        
            | 
            | 
           2461 | 
                * Allow to check for minimal Moodle version.
  | 
        
        
            | 
            | 
           2462 | 
                *
  | 
        
        
            | 
            | 
           2463 | 
                * @Given the site is running Moodle version :minversion or higher
  | 
        
        
            | 
            | 
           2464 | 
                * @param string $minversion The minimum version of Moodle required (inclusive).
  | 
        
        
            | 
            | 
           2465 | 
                */
  | 
        
        
            | 
            | 
           2466 | 
               public function the_site_is_running_moodle_version_or_higher(string $minversion): void {
  | 
        
        
            | 
            | 
           2467 | 
                   global $CFG;
  | 
        
        
            | 
            | 
           2468 | 
                   require_once($CFG->libdir . '/environmentlib.php');
  | 
        
        
            | 
            | 
           2469 | 
              | 
        
        
            | 
            | 
           2470 | 
                   $currentversion = normalize_version(get_config('', 'release'));
  | 
        
        
            | 
            | 
           2471 | 
              | 
        
        
            | 
            | 
           2472 | 
                   if (version_compare($currentversion, $minversion, '<')) {
  | 
        
        
            | 
            | 
           2473 | 
                       throw new Moodle\BehatExtension\Exception\SkippedException(
  | 
        
        
            | 
            | 
           2474 | 
                           'Site must be running Moodle version ' . $minversion . ' or higher'
  | 
        
        
            | 
            | 
           2475 | 
                       );
  | 
        
        
            | 
            | 
           2476 | 
                   }
  | 
        
        
            | 
            | 
           2477 | 
               }
  | 
        
        
            | 
            | 
           2478 | 
              | 
        
        
            | 
            | 
           2479 | 
               /**
  | 
        
        
            | 
            | 
           2480 | 
                * Allow to check for maximum Moodle version.
  | 
        
        
            | 
            | 
           2481 | 
                *
  | 
        
        
            | 
            | 
           2482 | 
                * @Given the site is running Moodle version :maxversion or lower
  | 
        
        
            | 
            | 
           2483 | 
                * @param string $maxversion The maximum version of Moodle required (inclusive).
  | 
        
        
            | 
            | 
           2484 | 
                */
  | 
        
        
            | 
            | 
           2485 | 
               public function the_site_is_running_moodle_version_or_lower(string $maxversion): void {
  | 
        
        
            | 
            | 
           2486 | 
                   global $CFG;
  | 
        
        
            | 
            | 
           2487 | 
                   require_once($CFG->libdir . '/environmentlib.php');
  | 
        
        
            | 
            | 
           2488 | 
              | 
        
        
            | 
            | 
           2489 | 
                   $currentversion = normalize_version(get_config('', 'release'));
  | 
        
        
            | 
            | 
           2490 | 
              | 
        
        
            | 
            | 
           2491 | 
                   if (version_compare($currentversion, $maxversion, '>')) {
  | 
        
        
            | 
            | 
           2492 | 
                       throw new Moodle\BehatExtension\Exception\SkippedException(
  | 
        
        
            | 
            | 
           2493 | 
                           'Site must be running Moodle version ' . $maxversion . ' or lower'
  | 
        
        
            | 
            | 
           2494 | 
                       );
  | 
        
        
            | 
            | 
           2495 | 
                   }
  | 
        
        
            | 
            | 
           2496 | 
               }
  | 
        
        
            | 
            | 
           2497 | 
              | 
        
        
            | 
            | 
           2498 | 
               /**
  | 
        
        
            | 
            | 
           2499 | 
                * Check that the page title contains a given string.
  | 
        
        
            | 
            | 
           2500 | 
                *
  | 
        
        
            | 
            | 
           2501 | 
                * @Given the page title should contain ":title"
  | 
        
        
            | 
            | 
           2502 | 
                * @param string $title The string that should be present on the page title.
  | 
        
        
            | 
            | 
           2503 | 
                */
  | 
        
        
            | 
            | 
           2504 | 
               public function the_page_title_should_contain(string $title): void {
  | 
        
        
            | 
            | 
           2505 | 
                   $session = $this->getSession();
  | 
        
        
            | 
            | 
           2506 | 
                   if ($this->running_javascript()) {
  | 
        
        
            | 
            | 
           2507 | 
                       // When running on JS, the page title can be changed via JS, so it's more reliable to get the actual page title via JS.
  | 
        
        
            | 
            | 
           2508 | 
                       $actualtitle = $session->evaluateScript("return document.title");
  | 
        
        
            | 
            | 
           2509 | 
                   } else {
  | 
        
        
            | 
            | 
           2510 | 
                       $titleelement = $session->getPage()->find('css', 'head title');
  | 
        
        
            | 
            | 
           2511 | 
                       if ($titleelement === null) {
  | 
        
        
            | 
            | 
           2512 | 
                           // Throw an exception if a page title is not present on the page.
  | 
        
        
            | 
            | 
           2513 | 
                           throw new ElementNotFoundException(
  | 
        
        
            | 
            | 
           2514 | 
                               $this->getSession(),
  | 
        
        
            | 
            | 
           2515 | 
                               '<title> element',
  | 
        
        
            | 
            | 
           2516 | 
                               'css',
  | 
        
        
            | 
            | 
           2517 | 
                               'head title'
  | 
        
        
            | 
            | 
           2518 | 
                           );
  | 
        
        
            | 
            | 
           2519 | 
                       }
  | 
        
        
            | 
            | 
           2520 | 
                       $actualtitle = $titleelement->getText();
  | 
        
        
            | 
            | 
           2521 | 
                   }
  | 
        
        
            | 
            | 
           2522 | 
              | 
        
        
            | 
            | 
           2523 | 
                   if (!str_contains($actualtitle, $title)) {
  | 
        
        
            | 
            | 
           2524 | 
                       throw new ExpectationException(
  | 
        
        
            | 
            | 
           2525 | 
                           "'$title' was not found from the current page title '$actualtitle'",
  | 
        
        
            | 
            | 
           2526 | 
                           $session
  | 
        
        
            | 
            | 
           2527 | 
                       );
  | 
        
        
            | 
            | 
           2528 | 
                   }
  | 
        
        
            | 
            | 
           2529 | 
               }
  | 
        
        
           | 1441 | 
           ariadna | 
           2530 | 
              | 
        
        
            | 
            | 
           2531 | 
               /**
  | 
        
        
            | 
            | 
           2532 | 
                * Toggles the specified admin switch.
  | 
        
        
            | 
            | 
           2533 | 
                *
  | 
        
        
            | 
            | 
           2534 | 
                * @When /^I toggle the "(?P<element_string>(?:[^"]|\\")*)" admin switch "(?P<state_string>on|off)"$/
  | 
        
        
            | 
            | 
           2535 | 
                * @param string $element Element we look for
  | 
        
        
            | 
            | 
           2536 | 
                * @param string $state The state of the switch
  | 
        
        
            | 
            | 
           2537 | 
                * @throws ElementNotFoundException Thrown by behat_base::find
  | 
        
        
            | 
            | 
           2538 | 
                */
  | 
        
        
            | 
            | 
           2539 | 
               public function i_toggle_admin_switch($element, $state) {
  | 
        
        
            | 
            | 
           2540 | 
                   // First check we are running Javascript, otherwise explode.
  | 
        
        
            | 
            | 
           2541 | 
                   if (!$this->running_javascript()) {
  | 
        
        
            | 
            | 
           2542 | 
                       throw new \Behat\Mink\Exception\DriverException('Switches are only available with JavaScript enabled');
  | 
        
        
            | 
            | 
           2543 | 
                   }
  | 
        
        
            | 
            | 
           2544 | 
              | 
        
        
            | 
            | 
           2545 | 
                   // Next check that the node is available.
  | 
        
        
            | 
            | 
           2546 | 
                   $node = $this->get_selected_node('checkbox', $element);
  | 
        
        
            | 
            | 
           2547 | 
                   $this->ensure_node_is_visible($node);
  | 
        
        
            | 
            | 
           2548 | 
              | 
        
        
            | 
            | 
           2549 | 
                   // Update the state of the switch.
  | 
        
        
            | 
            | 
           2550 | 
                   $field = $node->getAttribute('id');
  | 
        
        
            | 
            | 
           2551 | 
                   if ($state == "on") {
  | 
        
        
            | 
            | 
           2552 | 
                       $this->execute([behat_forms::class, 'i_set_the_field_to'], [$field, 1]);
  | 
        
        
            | 
            | 
           2553 | 
                   } else if ($state == "off") {
  | 
        
        
            | 
            | 
           2554 | 
                       $this->execute([behat_forms::class, 'i_set_the_field_to'], [$field, 0]);
  | 
        
        
            | 
            | 
           2555 | 
                   } else {
  | 
        
        
            | 
            | 
           2556 | 
                       throw new \Behat\Mink\Exception\ExpectationException('Invalid state for switch: ' . $state, $this->getSession());
  | 
        
        
            | 
            | 
           2557 | 
                   }
  | 
        
        
            | 
            | 
           2558 | 
              | 
        
        
            | 
            | 
           2559 | 
               }
  | 
        
        
            | 
            | 
           2560 | 
              | 
        
        
            | 
            | 
           2561 | 
               /**
  | 
        
        
            | 
            | 
           2562 | 
                * Update a stored progress bar.
  | 
        
        
            | 
            | 
           2563 | 
                *
  | 
        
        
            | 
            | 
           2564 | 
                * @Given I set the stored progress bar :idnumber to :percent
  | 
        
        
            | 
            | 
           2565 | 
                * @param string $idnumber The unique idnumber of the stored progress bar.
  | 
        
        
            | 
            | 
           2566 | 
                * @param float $percent The value to update the progress bar to.
  | 
        
        
            | 
            | 
           2567 | 
                */
  | 
        
        
            | 
            | 
           2568 | 
               public function i_set_the_stored_progress_bar_to(string $idnumber, float $percent): void {
  | 
        
        
            | 
            | 
           2569 | 
                   $progress = \core\output\stored_progress_bar::get_by_idnumber($idnumber);
  | 
        
        
            | 
            | 
           2570 | 
                   if (!$progress) {
  | 
        
        
            | 
            | 
           2571 | 
                       throw new invalid_parameter_exception('No progress bar with idnumber ' . $idnumber . 'found.');
  | 
        
        
            | 
            | 
           2572 | 
                   }
  | 
        
        
            | 
            | 
           2573 | 
                   $progress->auto_update(false);
  | 
        
        
            | 
            | 
           2574 | 
                   $progress->update_full($percent, '');
  | 
        
        
            | 
            | 
           2575 | 
               }
  | 
        
        
            | 
            | 
           2576 | 
              | 
        
        
            | 
            | 
           2577 | 
               /**
  | 
        
        
            | 
            | 
           2578 | 
                * Helper that returns the dropdown node element within a particular search combo box.
  | 
        
        
            | 
            | 
           2579 | 
                *
  | 
        
        
            | 
            | 
           2580 | 
                * @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
  | 
        
        
            | 
            | 
           2581 | 
                * @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
  | 
        
        
            | 
            | 
           2582 | 
                *                         to true.
  | 
        
        
            | 
            | 
           2583 | 
                * @param bool $fieldset Whether to set the search field of the combo box at the same time
  | 
        
        
            | 
            | 
           2584 | 
                * @return NodeElement
  | 
        
        
            | 
            | 
           2585 | 
                * @throws coding_exception
  | 
        
        
            | 
            | 
           2586 | 
                */
  | 
        
        
            | 
            | 
           2587 | 
               private function get_combobox_dropdown_node(string $comboboxname, string $itemname, bool $fieldset = true): NodeElement {
  | 
        
        
            | 
            | 
           2588 | 
                   $this->execute([self::class, 'wait_until_the_page_is_ready']);
  | 
        
        
            | 
            | 
           2589 | 
              | 
        
        
            | 
            | 
           2590 | 
                   $comboboxxpath = "//div[contains(@class, 'comboboxsearch') and .//span[text()='{$comboboxname}']]";
  | 
        
        
            | 
            | 
           2591 | 
                   $dropdowntriggerxpath = $comboboxxpath . "/descendant::div[contains(@class,'dropdown-toggle')]";
  | 
        
        
            | 
            | 
           2592 | 
                   $dropdownxpath = $comboboxxpath . "/descendant::div[contains(@class,'dropdown-menu')]";
  | 
        
        
            | 
            | 
           2593 | 
                   $dropdown = $this->find("xpath_element", $dropdownxpath);
  | 
        
        
            | 
            | 
           2594 | 
              | 
        
        
            | 
            | 
           2595 | 
                   // If the dropdown is not visible, open it. Also, ensure that a dropdown trigger element exists.
  | 
        
        
            | 
            | 
           2596 | 
                   if ($this->getSession()->getPage()->find('xpath', $dropdowntriggerxpath) && !$dropdown->isVisible()) {
  | 
        
        
            | 
            | 
           2597 | 
                       $this->execute([self::class, 'i_click_on'], [$dropdowntriggerxpath, "xpath_element"]);
  | 
        
        
            | 
            | 
           2598 | 
                   }
  | 
        
        
            | 
            | 
           2599 | 
              | 
        
        
            | 
            | 
           2600 | 
                   if ($fieldset) {
  | 
        
        
            | 
            | 
           2601 | 
                       $this->execute([behat_forms::class, 'set_field_value'], [$comboboxname, $itemname]);
  | 
        
        
            | 
            | 
           2602 | 
                       $this->execute([self::class, 'wait_until_exists'], [$itemname, "list_item"]);
  | 
        
        
            | 
            | 
           2603 | 
                   }
  | 
        
        
            | 
            | 
           2604 | 
              | 
        
        
            | 
            | 
           2605 | 
                   return $dropdown;
  | 
        
        
            | 
            | 
           2606 | 
               }
  | 
        
        
            | 
            | 
           2607 | 
              | 
        
        
            | 
            | 
           2608 | 
               /**
  | 
        
        
            | 
            | 
           2609 | 
                * Confirm if a value exists within the search combo box.
  | 
        
        
            | 
            | 
           2610 | 
                *
  | 
        
        
            | 
            | 
           2611 | 
                * Examples:
  | 
        
        
            | 
            | 
           2612 | 
                * - I confirm "User" exists in the "Search users" search combo box
  | 
        
        
            | 
            | 
           2613 | 
                * - I confirm "Group" exists in the "Search groups" search combo box
  | 
        
        
            | 
            | 
           2614 | 
                * - I confirm "Grade item" exists in the "Search grade items" search combo box
  | 
        
        
            | 
            | 
           2615 | 
                *
  | 
        
        
            | 
            | 
           2616 | 
                * @Given /^I confirm "(?P<itemname>(?:[^"]|\\")*)" exists in the "(?P<comboboxname>(?:[^"]|\\")*)" search combo box$/
  | 
        
        
            | 
            | 
           2617 | 
                * @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
  | 
        
        
            | 
            | 
           2618 | 
                *                         to true.
  | 
        
        
            | 
            | 
           2619 | 
                * @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
  | 
        
        
            | 
            | 
           2620 | 
                */
  | 
        
        
            | 
            | 
           2621 | 
               public function i_confirm_in_search_combobox_exists(string $itemname, string $comboboxname): void {
  | 
        
        
            | 
            | 
           2622 | 
                   $this->execute([self::class, 'assert_element_contains_text'],
  | 
        
        
            | 
            | 
           2623 | 
                       [$itemname, $this->get_combobox_dropdown_node($comboboxname, $itemname, false), "NodeElement"]);
  | 
        
        
            | 
            | 
           2624 | 
               }
  | 
        
        
            | 
            | 
           2625 | 
              | 
        
        
            | 
            | 
           2626 | 
               /**
  | 
        
        
            | 
            | 
           2627 | 
                * Confirm if a value does not exist within the search combo box.
  | 
        
        
            | 
            | 
           2628 | 
                *
  | 
        
        
            | 
            | 
           2629 | 
                * Examples:
  | 
        
        
            | 
            | 
           2630 | 
                * - I confirm "User" does not exist in the "Search users" search combo box
  | 
        
        
            | 
            | 
           2631 | 
                * - I confirm "Group" does not exist in the "Search groups" search combo box
  | 
        
        
            | 
            | 
           2632 | 
                * - I confirm "Grade item" does not exist in the "Search grade items" search combo box
  | 
        
        
            | 
            | 
           2633 | 
                *
  | 
        
        
            | 
            | 
           2634 | 
                * @Given /^I confirm "(?P<itemname>(?:[^"]|\\")*)" does not exist in the "(?P<comboboxname>(?:[^"]|\\")*)" search combo box$/
  | 
        
        
            | 
            | 
           2635 | 
                * @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
  | 
        
        
            | 
            | 
           2636 | 
                *                         to true.
  | 
        
        
            | 
            | 
           2637 | 
                * @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
  | 
        
        
            | 
            | 
           2638 | 
                */
  | 
        
        
            | 
            | 
           2639 | 
               public function i_confirm_in_search_combobox_does_not_exist(string $itemname, string $comboboxname): void {
  | 
        
        
            | 
            | 
           2640 | 
                   $this->execute([self::class, 'assert_element_not_contains_text'],
  | 
        
        
            | 
            | 
           2641 | 
                       [$itemname, $this->get_combobox_dropdown_node($comboboxname, $itemname, false), "NodeElement"]);
  | 
        
        
            | 
            | 
           2642 | 
               }
  | 
        
        
            | 
            | 
           2643 | 
              | 
        
        
            | 
            | 
           2644 | 
               /**
  | 
        
        
            | 
            | 
           2645 | 
                * Clicks on an option from the specified search widget.
  | 
        
        
            | 
            | 
           2646 | 
                *
  | 
        
        
            | 
            | 
           2647 | 
                * Examples:
  | 
        
        
            | 
            | 
           2648 | 
                * - I click on "Student" in the "Search users" search combo box
  | 
        
        
            | 
            | 
           2649 | 
                * - I click on "Group" in the "Search groups" search combo box
  | 
        
        
            | 
            | 
           2650 | 
                * - I click on "Grade item" in the "Search grade items" search combo box
  | 
        
        
            | 
            | 
           2651 | 
                *
  | 
        
        
            | 
            | 
           2652 | 
                * @Given /^I click on "(?P<itemname>(?:[^"]|\\")*)" in the "(?P<comboboxname>(?:[^"]|\\")*)" search combo box$/
  | 
        
        
            | 
            | 
           2653 | 
                * @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
  | 
        
        
            | 
            | 
           2654 | 
                *                         to true.
  | 
        
        
            | 
            | 
           2655 | 
                * @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
  | 
        
        
            | 
            | 
           2656 | 
                */
  | 
        
        
            | 
            | 
           2657 | 
               public function i_click_on_in_search_combobox(string $itemname, string $comboboxname): void {
  | 
        
        
            | 
            | 
           2658 | 
                   $node = $this->get_combobox_dropdown_node($comboboxname, $itemname);
  | 
        
        
            | 
            | 
           2659 | 
                   $this->execute([self::class, 'i_click_on_in_the'], [
  | 
        
        
            | 
            | 
           2660 | 
                       $itemname, "list_item",
  | 
        
        
            | 
            | 
           2661 | 
                       $node, "NodeElement",
  | 
        
        
            | 
            | 
           2662 | 
                   ]);
  | 
        
        
            | 
            | 
           2663 | 
                   $this->execute([self::class, 'i_wait_to_be_redirected']);
  | 
        
        
            | 
            | 
           2664 | 
               }
  | 
        
        
            | 
            | 
           2665 | 
              | 
        
        
            | 
            | 
           2666 | 
               /**
  | 
        
        
            | 
            | 
           2667 | 
                * Clicks on a specific link within a table row.
  | 
        
        
            | 
            | 
           2668 | 
                * Good for clicking links on tables where links have repeated text in diiferent rows.
  | 
        
        
            | 
            | 
           2669 | 
                *
  | 
        
        
            | 
            | 
           2670 | 
                * Example:
  | 
        
        
            | 
            | 
           2671 | 
                * - I click on the "Settings" link in the row containing "Text editor placement"
  | 
        
        
            | 
            | 
           2672 | 
                *
  | 
        
        
            | 
            | 
           2673 | 
                * @Given /^I click on the "(?P<linktext>(?:[^"]|\\")*)" link in the table row containing "(?P<rowtext>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           2674 | 
                * @param string $linktext
  | 
        
        
            | 
            | 
           2675 | 
                * @param string $rowtext
  | 
        
        
            | 
            | 
           2676 | 
                */
  | 
        
        
            | 
            | 
           2677 | 
               public function i_click_on_the_link_in_the_table_row_containing(string $linktext, string $rowtext): void {
  | 
        
        
            | 
            | 
           2678 | 
                   $row = $this->getSession()->getPage()->find('xpath', "//tr[contains(., '{$rowtext}')]");
  | 
        
        
            | 
            | 
           2679 | 
                   if (!$row) {
  | 
        
        
            | 
            | 
           2680 | 
                       throw new Exception("Row containing '{$rowtext}' not found");
  | 
        
        
            | 
            | 
           2681 | 
                   }
  | 
        
        
            | 
            | 
           2682 | 
                   $link = $row->findLink($linktext);
  | 
        
        
            | 
            | 
           2683 | 
                   if (!$link) {
  | 
        
        
            | 
            | 
           2684 | 
                       throw new Exception("Link '{$linktext}' not found in the row containing '{$rowtext}'");
  | 
        
        
            | 
            | 
           2685 | 
                   }
  | 
        
        
            | 
            | 
           2686 | 
                   $link->click();
  | 
        
        
            | 
            | 
           2687 | 
               }
  | 
        
        
            | 
            | 
           2688 | 
              | 
        
        
            | 
            | 
           2689 | 
               /**
  | 
        
        
            | 
            | 
           2690 | 
                * Checks if a specific text is present in a table row.
  | 
        
        
            | 
            | 
           2691 | 
                * Good for checking text in tables where text is repeated in different rows.
  | 
        
        
            | 
            | 
           2692 | 
                *
  | 
        
        
            | 
            | 
           2693 | 
                * Example:
  | 
        
        
            | 
            | 
           2694 | 
                * - I should see "This action is unavailable." in the table row containing "Generate text"
  | 
        
        
            | 
            | 
           2695 | 
                *
  | 
        
        
            | 
            | 
           2696 | 
                * @Then /^I should see "(?P<text>(?:[^"]|\\")*)" in the table row containing "(?P<rowtext>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           2697 | 
                * @param string $text
  | 
        
        
            | 
            | 
           2698 | 
                * @param string $rowtext
  | 
        
        
            | 
            | 
           2699 | 
                */
  | 
        
        
            | 
            | 
           2700 | 
               public function i_should_see_in_the_table_row_containing(string $text, string $rowtext): void {
  | 
        
        
            | 
            | 
           2701 | 
                   $row = $this->getSession()->getPage()->find('xpath', "//tr[contains(., '{$rowtext}')]");
  | 
        
        
            | 
            | 
           2702 | 
                   if (!$row) {
  | 
        
        
            | 
            | 
           2703 | 
                       throw new Exception("Row containing '{$rowtext}' not found");
  | 
        
        
            | 
            | 
           2704 | 
                   }
  | 
        
        
            | 
            | 
           2705 | 
                   if (strpos($row->getText(), $text) === false) {
  | 
        
        
            | 
            | 
           2706 | 
                       throw new Exception("Text '{$text}' not found in the row containing '{$rowtext}'");
  | 
        
        
            | 
            | 
           2707 | 
                   }
  | 
        
        
            | 
            | 
           2708 | 
               }
  | 
        
        
            | 
            | 
           2709 | 
              | 
        
        
            | 
            | 
           2710 | 
               /**
  | 
        
        
            | 
            | 
           2711 | 
                * Checks if a specific text is not present in a table row.
  | 
        
        
            | 
            | 
           2712 | 
                * Good for checking text in tables where text is repeated in different rows.
  | 
        
        
            | 
            | 
           2713 | 
                *
  | 
        
        
            | 
            | 
           2714 | 
                * Example:
  | 
        
        
            | 
            | 
           2715 | 
                * - I should not see "This action is unavailable." in the table row containing "Generate text"
  | 
        
        
            | 
            | 
           2716 | 
                *
  | 
        
        
            | 
            | 
           2717 | 
                * @Then /^I should not see "(?P<text>(?:[^"]|\\")*)" in the table row containing "(?P<rowtext>(?:[^"]|\\")*)"$/
  | 
        
        
            | 
            | 
           2718 | 
                * @param string $text
  | 
        
        
            | 
            | 
           2719 | 
                * @param string $rowtext
  | 
        
        
            | 
            | 
           2720 | 
                */
  | 
        
        
            | 
            | 
           2721 | 
               public function i_should_not_see_in_the_table_row_containing(string $text, string $rowtext): void {
  | 
        
        
            | 
            | 
           2722 | 
                   $row = $this->getSession()->getPage()->find('xpath', "//tr[contains(., '{$rowtext}')]");
  | 
        
        
            | 
            | 
           2723 | 
                   if (!$row) {
  | 
        
        
            | 
            | 
           2724 | 
                       throw new Exception("Row containing '{$rowtext}' not found");
  | 
        
        
            | 
            | 
           2725 | 
                   }
  | 
        
        
            | 
            | 
           2726 | 
                   if (strpos($row->getText(), $text) !== false) {
  | 
        
        
            | 
            | 
           2727 | 
                       throw new Exception("Text '{$text}' found in the row containing '{$rowtext}'");
  | 
        
        
            | 
            | 
           2728 | 
                   }
  | 
        
        
            | 
            | 
           2729 | 
               }
  | 
        
        
            | 
            | 
           2730 | 
              | 
        
        
            | 
            | 
           2731 | 
               /**
  | 
        
        
            | 
            | 
           2732 | 
                * Sets the current time for the remainder of this Behat test.
  | 
        
        
            | 
            | 
           2733 | 
                *
  | 
        
        
            | 
            | 
           2734 | 
                * This is not supported everywhere in Moodle: if code uses \core\clock through DI then
  | 
        
        
            | 
            | 
           2735 | 
                * it will work, but if it just calls time() it will still get the real time.
  | 
        
        
            | 
            | 
           2736 | 
                *
  | 
        
        
            | 
            | 
           2737 | 
                * @Given the time is frozen at :datetime
  | 
        
        
            | 
            | 
           2738 | 
                * @param string $datetime Date and time in a format that strtotime understands
  | 
        
        
            | 
            | 
           2739 | 
                */
  | 
        
        
            | 
            | 
           2740 | 
               public function the_time_is_frozen_at(string $datetime): void {
  | 
        
        
            | 
            | 
           2741 | 
                   global $CFG;
  | 
        
        
            | 
            | 
           2742 | 
                   require_once($CFG->libdir . '/testing/classes/frozen_clock.php');
  | 
        
        
            | 
            | 
           2743 | 
              | 
        
        
            | 
            | 
           2744 | 
                   $timestamp = strtotime($datetime);
  | 
        
        
            | 
            | 
           2745 | 
                   // The config variable is used to set up a frozen clock in each Behat web request.
  | 
        
        
            | 
            | 
           2746 | 
                   set_config('behat_frozen_clock', $timestamp);
  | 
        
        
            | 
            | 
           2747 | 
                   // Simply setting a frozen clock in DI should work for future steps in Behat CLI process.
  | 
        
        
            | 
            | 
           2748 | 
                   \core\di::set(\core\clock::class, new \frozen_clock($timestamp));
  | 
        
        
            | 
            | 
           2749 | 
               }
  | 
        
        
            | 
            | 
           2750 | 
              | 
        
        
            | 
            | 
           2751 | 
               /**
  | 
        
        
            | 
            | 
           2752 | 
                * Stops freezing time so that it goes back to real time.
  | 
        
        
            | 
            | 
           2753 | 
                *
  | 
        
        
            | 
            | 
           2754 | 
                * @Given the time is no longer frozen
  | 
        
        
            | 
            | 
           2755 | 
                */
  | 
        
        
            | 
            | 
           2756 | 
               public function the_time_is_no_longer_frozen(): void {
  | 
        
        
            | 
            | 
           2757 | 
                   unset_config('behat_frozen_clock');
  | 
        
        
            | 
            | 
           2758 | 
                   \core\di::set(\core\clock::class, new \core\system_clock());
  | 
        
        
            | 
            | 
           2759 | 
               }
  | 
        
        
           | 1 | 
           efrain | 
           2760 | 
           }
  |