Пример #1
0
 /**
  * Add the specified user to the group. You should be in the groups page when running this step. The user should be specified like "Firstname Lastname (user@example.com)".
  *
  * @Given /^I add "(?P<user_fullname_string>(?:[^"]|\\")*)" user to "(?P<group_name_string>(?:[^"]|\\")*)" group members$/
  * @throws ElementNotFoundException Thrown by behat_base::find
  * @param string $username
  * @param string $groupname
  */
 public function i_add_user_to_group_members($userfullname, $groupname)
 {
     $userfullname = behat_context_helper::escape($userfullname);
     // Using a xpath liternal to avoid problems with quotes and double quotes.
     $groupname = behat_context_helper::escape($groupname);
     // We don't know the option text as it contains the number of users in the group.
     $select = $this->find_field('groups');
     $xpath = "//select[@id='groups']/descendant::option[contains(., {$groupname})]";
     $groupoption = $this->find('xpath', $xpath);
     $fulloption = $groupoption->getText();
     $select->selectOption($fulloption);
     // This is needed by some drivers to ensure relevant event is triggred and button is enabled.
     $script = "Syn.trigger('change', {}, {{ELEMENT}})";
     $this->getSession()->getDriver()->triggerSynScript($select->getXpath(), $script);
     $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
     // Here we don't need to wait for the AJAX response.
     $this->find_button(get_string('adduserstogroup', 'group'))->click();
     // Wait for add/remove members page to be loaded.
     $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
     // Getting the option and selecting it.
     $select = $this->find_field('addselect');
     $xpath = "//select[@id='addselect']/descendant::option[contains(., {$userfullname})]";
     $memberoption = $this->find('xpath', $xpath);
     $fulloption = $memberoption->getText();
     $select->selectOption($fulloption);
     // Click add button.
     $this->find_button(get_string('add'))->click();
     // Wait for the page to load.
     $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
     // Returning to the main groups page.
     $this->find_button(get_string('backtogroups', 'group'))->click();
 }
 /**
  * Manually adds a reviewer for workshop participant.
  *
  * This step should start on manual allocation page.
  *
  * @When /^I add a reviewer "(?P<reviewer_name_string>(?:[^"]|\\")*)" for workshop participant "(?P<participant_name_string>(?:[^"]|\\")*)"$/
  * @param string $reviewername
  * @param string $participantname
  */
 public function i_add_a_reviewer_for_workshop_participant($reviewername, $participantname)
 {
     $participantnameliteral = behat_context_helper::escape($participantname);
     $xpathtd = "//table[contains(concat(' ', normalize-space(@class), ' '), ' allocations ')]/" . "tbody/tr[./td[contains(concat(' ', normalize-space(@class), ' '), ' peer ')]" . "[contains(.,{$participantnameliteral})]]/" . "td[contains(concat(' ', normalize-space(@class), ' '), ' reviewedby ')]";
     $xpathselect = $xpathtd . "/descendant::select";
     try {
         $selectnode = $this->find('xpath', $xpathselect);
     } catch (Exception $ex) {
         $this->find_button(get_string('showallparticipants', 'workshopallocation_manual'))->press();
         $selectnode = $this->find('xpath', $xpathselect);
     }
     $selectformfield = behat_field_manager::get_form_field($selectnode, $this->getSession());
     $selectformfield->set_value($reviewername);
     if (!$this->running_javascript()) {
         // Without Javascript we need to press the "Go" button.
         $go = behat_context_helper::escape(get_string('go'));
         $this->find('xpath', $xpathtd . "/descendant::input[@value={$go}]")->click();
     } else {
         // With Javascript we just wait for the page to reload.
         $this->getSession()->wait(self::EXTENDED_TIMEOUT, self::PAGE_READY_JS);
     }
     // Check the success string to appear.
     $allocatedtext = behat_context_helper::escape(get_string('allocationadded', 'workshopallocation_manual'));
     $this->find('xpath', "//*[contains(.,{$allocatedtext})]");
 }
Пример #3
0
 /**
  * Checks that the specified user has not completed the specified activity of the current course.
  *
  * @Then /^"(?P<user_fullname_string>(?:[^"]|\\")*)" user has not completed "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
  * @param string $userfullname
  * @param string $activityname
  */
 public function user_has_not_completed_activity($userfullname, $activityname)
 {
     // Will throw an exception if the element can not be hovered.
     $titleliteral = behat_context_helper::escape($userfullname . ", " . $activityname . ": Not completed");
     $xpath = "//table[@id='completion-progress']" . "/descendant::img[contains(@title, {$titleliteral})]";
     $this->execute("behat_completion::go_to_the_current_course_activity_completion_report");
     $this->execute("behat_general::should_exist", array($this->escape($xpath), "xpath_element"));
 }
 public function i_should_see_question_in_section_in_the_quiz_navigation($questionnumber, $sectionheading)
 {
     // Using xpath literal to avoid quotes problems.
     $questionnumberliteral = behat_context_helper::escape('Question ' . $questionnumber);
     $headingliteral = behat_context_helper::escape($sectionheading);
     // Split in two checkings to give more feedback in case of exception.
     $exception = new ExpectationException('Question "' . $questionnumber . '" is not in section "' . $sectionheading . '" in the quiz navigation.', $this->getSession());
     $xpath = "//*[@id = 'mod_quiz_navblock']//*[contains(concat(' ', normalize-space(@class), ' '), ' qnbutton ') and " . "contains(., {$questionnumberliteral}) and contains(preceding-sibling::h3[1], {$headingliteral})]";
     $this->find('xpath', $xpath);
 }
 protected function get_top_navigation_node($nodetext)
 {
     // Avoid problems with quotes.
     $nodetextliteral = behat_context_helper::escape($nodetext);
     $exception = new ExpectationException('Top navigation node "' . $nodetext . ' not found in "', $this->getSession());
     // First find in navigation block.
     $xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' card-text ')]" . "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" . "/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" . "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" . "[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" . "/span[normalize-space(.)=" . $nodetextliteral . "]]" . "|" . "//div[contains(concat(' ', normalize-space(@class), ' '), ' card-text ')]/div" . "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" . "/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" . "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" . "[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" . "/span[normalize-space(.)=" . $nodetextliteral . "]]" . "|" . "//div[contains(concat(' ', normalize-space(@class), ' '), ' card-text ')]/div" . "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" . "/li[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" . "/span[normalize-space(.)=" . $nodetextliteral . "]]" . "|" . "//div[contains(concat(' ', normalize-space(@class), ' '), ' card-text ')]/div" . "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" . "/li[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" . "/a[normalize-space(.)=" . $nodetextliteral . "]]";
     $node = $this->find('xpath', $xpath, $exception);
     return $node;
 }
Пример #6
0
 /**
  * Sets the value(s) of an availability element.
  *
  * At present this only supports the following value 'Grouping: xxx' where
  * xxx is the name of a grouping. Additional value types can be added as
  * necessary.
  *
  * @param string $value Value code
  * @return void
  */
 public function set_value($value)
 {
     global $DB;
     $driver = $this->session->getDriver();
     // Check the availability condition is currently unset - we don't yet
     // support changing an existing one.
     $existing = $this->get_value();
     if ($existing && $existing !== '{"op":"&","c":[],"showc":[]}') {
         throw new Exception('Cannot automatically set availability when ' . 'there is existing setting - must clear manually');
     }
     // Check the value matches a supported format.
     $matches = array();
     if (!preg_match('~^\\s*([^:]*):\\s*(.*?)\\s*$~', $value, $matches)) {
         throw new Exception('Value for availability field does not match correct ' . 'format. Example: "Grouping: G1"');
     }
     $type = $matches[1];
     $param = $matches[2];
     if ($this->running_javascript()) {
         switch (strtolower($type)) {
             case 'grouping':
                 // Set a grouping condition.
                 $driver->click('//div[@class="availability-button"]/button');
                 $driver->click('//button[@id="availability_addrestriction_grouping"]');
                 $escparam = behat_context_helper::escape($param);
                 $nodes = $driver->find('//span[contains(concat(" " , @class, " "), " availability_grouping ")]//' . 'option[normalize-space(.) = ' . $escparam . ']');
                 if (count($nodes) != 1) {
                     throw new Exception('Cannot find grouping in dropdown' . count($nodes));
                 }
                 $node = reset($nodes);
                 $value = $node->getValue();
                 $driver->selectOption('//span[contains(concat(" " , @class, " "), " availability_grouping ")]//' . 'select', $value);
                 break;
             default:
                 // We don't support other types yet. The test author must write
                 // manual 'click on that button, etc' commands.
                 throw new Exception('The availability type "' . $type . '" is currently not supported - must set manually');
         }
     } else {
         $courseid = $driver->getValue('//input[@name="course"]');
         switch (strtolower($type)) {
             case 'grouping':
                 // Define result with one grouping condition.
                 $groupingid = $DB->get_field('groupings', 'id', array('courseid' => $courseid, 'name' => $param));
                 $json = \core_availability\tree::get_root_json(array(\availability_grouping\condition::get_json($groupingid)));
                 break;
             default:
                 // We don't support other types yet.
                 throw new Exception('The availability type "' . $type . '" is currently not supported - must set with JavaScript');
         }
         $driver->setValue('//textarea[@name="availabilityconditionsjson"]', json_encode($json));
     }
 }
Пример #7
0
 /**
  * Returns the behat selector and locator for a given moodle selector and locator
  *
  * @param string $selectortype The moodle selector type, which includes moodle selectors
  * @param string $element The locator we look for in that kind of selector
  * @param Session $session The Mink opened session
  * @return array Contains the selector and the locator expected by Mink.
  */
 public static function get_behat_selector($selectortype, $element, Behat\Mink\Session $session)
 {
     // CSS and XPath selectors locator is one single argument.
     if ($selectortype == 'css_element' || $selectortype == 'xpath_element') {
         $selector = str_replace('_element', '', $selectortype);
         $locator = $element;
     } else {
         // Named selectors uses arrays as locators including the type of named selector.
         $locator = array($selectortype, behat_context_helper::escape($element));
         $selector = 'named_partial';
     }
     return array($selector, $locator);
 }
Пример #8
0
 /**
  * Checks the state of the specified question.
  *
  * @Then /^the state of "(?P<question_description_string>(?:[^"]|\\")*)" question is shown as "(?P<state_string>(?:[^"]|\\")*)"$/
  * @throws ExpectationException
  * @throws ElementNotFoundException
  * @param string $questiondescription
  * @param string $state
  */
 public function the_state_of_question_is_shown_as($questiondescription, $state)
 {
     // Using xpath literal to avoid quotes problems.
     $questiondescriptionliteral = behat_context_helper::escape($questiondescription);
     $stateliteral = behat_context_helper::escape($state);
     // Split in two checkings to give more feedback in case of exception.
     $exception = new ElementNotFoundException($this->getSession(), 'Question "' . $questiondescription . '" ');
     $questionxpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' que ')]" . "[contains(div[@class='content']/div[contains(concat(' ', normalize-space(@class), ' '), ' formulation ')]," . "{$questiondescriptionliteral})]";
     $this->find('xpath', $questionxpath, $exception);
     $exception = new ExpectationException('Question "' . $questiondescription . '" state is not "' . $state . '"', $this->getSession());
     $xpath = $questionxpath . "/div[@class='info']/div[@class='state' and contains(., {$stateliteral})]";
     $this->find('xpath', $xpath, $exception);
 }
Пример #9
0
 /**
  * Deletes the specified comment from the current page's comments block.
  *
  * @Given /^I delete "(?P<comment_text_string>(?:[^"]|\\")*)" comment from comments block$/
  * @throws ElementNotFoundException
  * @throws ExpectationException
  * @param string $comment
  */
 public function i_delete_comment_from_comments_block($comment)
 {
     $exception = new ElementNotFoundException($this->getSession(), '"' . $comment . '" comment ');
     // Using xpath liternal to avoid possible problems with comments containing quotes.
     $commentliteral = behat_context_helper::escape($comment);
     $commentxpath = "//*[contains(concat(' ', normalize-space(@class), ' '), ' block_comments ')]" . "/descendant::div[@class='comment-message'][contains(., {$commentliteral})]";
     $commentnode = $this->find('xpath', $commentxpath, $exception);
     // Click on delete icon.
     $deleteexception = new ExpectationException('"' . $comment . '" comment can not be deleted', $this->getSession());
     $deleteicon = $this->find('css', '.comment-delete a img', $deleteexception, $commentnode);
     $deleteicon->click();
     // Wait for the animation to finish, in theory is just 1 sec, adding 4 just in case.
     $this->getSession()->wait(4 * 1000, false);
 }
 protected function get_filepicker_node($filepickerelement)
 {
     // More info about the problem (in case there is a problem).
     $exception = new ExpectationException('"' . $filepickerelement . '" filepicker can not be found', $this->getSession());
     // If no file picker label is mentioned take the first file picker from the page.
     if (empty($filepickerelement)) {
         $filepickercontainer = $this->find('xpath', "//*[@data-fieldtype=\"filemanager\"]", $exception);
     } else {
         // Gets the ffilemanager node specified by the locator which contains the filepicker container.
         $filepickerelement = behat_context_helper::escape($filepickerelement);
         $filepickercontainer = $this->find('xpath', "//input[./@id = //label[normalize-space(.)={$filepickerelement}]/@for]" . "//ancestor::*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker']", $exception);
     }
     return $filepickercontainer;
 }
 public function i_set_the_following_administration_settings_values(TableNode $table)
 {
     if (!($data = $table->getRowsHash())) {
         return;
     }
     foreach ($data as $label => $value) {
         // We expect admin block to be visible, otherwise go to homepage.
         if (!$this->getSession()->getPage()->find('css', '.block_settings')) {
             $this->getSession()->visit($this->locate_path('/'));
             $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
         }
         // Search by label.
         $searchbox = $this->find_field(get_string('searchinsettings', 'admin'));
         $searchbox->setValue($label);
         $submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]');
         $submitsearch->press();
         $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
         // Admin settings does not use the same DOM structure than other moodle forms
         // but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
         $exception = new ElementNotFoundException($this->getSession(), '"' . $label . '" administration setting ');
         // The argument should be converted to an xpath literal.
         $label = behat_context_helper::escape($label);
         // Single element settings.
         try {
             $fieldxpath = "//*[self::input | self::textarea | self::select]" . "[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" . "[@id=//label[contains(normalize-space(.), {$label})]/@for or " . "@id=//span[contains(normalize-space(.), {$label})]/preceding-sibling::label[1]/@for]";
             $fieldnode = $this->find('xpath', $fieldxpath, $exception);
             $formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[contains(concat(' ', @class, ' '), ' form-setting ')]" . "/child::div[contains(concat(' ', @class, ' '),  ' form-')]/child::*/parent::div");
         } catch (ElementNotFoundException $e) {
             // Multi element settings, interacting only the first one.
             $fieldxpath = "//*[label[contains(., {$label})]|span[contains(., {$label})]]" . "/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" . "/descendant::div[contains(concat(' ', @class, ' '), ' form-group ')]" . "/descendant::*[self::input | self::textarea | self::select]" . "[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
             $fieldnode = $this->find('xpath', $fieldxpath);
             // It is the same one that contains the type.
             $formfieldtypenode = $fieldnode;
         }
         // Getting the class which contains the field type.
         $classes = explode(' ', $formfieldtypenode->getAttribute('class'));
         $type = false;
         foreach ($classes as $class) {
             if (substr($class, 0, 5) == 'form-') {
                 $type = substr($class, 5);
             }
         }
         // Instantiating the appropiate field type.
         $field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession());
         $field->set_value($value);
         $this->find_button(get_string('savechanges'))->press();
     }
 }
Пример #12
0
 /**
  * Opens the contents of a filemanager folder. It looks for the folder in the current folder and in the path bar.
  *
  * @Given /^I open "(?P<foldername_string>(?:[^"]|\\")*)" folder from "(?P<filemanager_field_string>(?:[^"]|\\")*)" filemanager$/
  * @throws ExpectationException Thrown by behat_base::find
  * @param string $foldername
  * @param string $filemanagerelement
  */
 public function i_open_folder_from_filemanager($foldername, $filemanagerelement)
 {
     $fieldnode = $this->get_filepicker_node($filemanagerelement);
     $exception = new ExpectationException('The "' . $foldername . '" folder can not be found in the "' . $filemanagerelement . '" filemanager', $this->getSession());
     $folderliteral = behat_context_helper::escape($foldername);
     // We look both in the pathbar and in the contents.
     try {
         // In the current folder workspace.
         $folder = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')]" . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-filename ')]" . "[normalize-space(.)={$folderliteral}]", $exception, $fieldnode);
     } catch (ExpectationException $e) {
         // And in the pathbar.
         $folder = $this->find('xpath', "//a[contains(concat(' ', normalize-space(@class), ' '), ' fp-path-folder-name ')]" . "[normalize-space(.)={$folderliteral}]", $exception, $fieldnode);
     }
     // It should be a NodeElement, otherwise an exception would have been thrown.
     $folder->click();
 }
Пример #13
0
 /**
  * Enrols the specified user in the current course without options.
  *
  * This is a simple step, to set enrolment options would be better to
  * create a separate step as a TableNode will be required.
  *
  * @Given /^I enrol "(?P<user_fullname_string>(?:[^"]|\\")*)" user as "(?P<rolename_string>(?:[^"]|\\")*)"$/
  * @param string $userfullname
  * @param string $rolename
  */
 public function i_enrol_user_as($userfullname, $rolename)
 {
     // Navigate to enrolment page.
     $parentnodes = get_string('courseadministration') . ' > ' . get_string('users', 'admin');
     $this->execute("behat_navigation::i_navigate_to_node_in", array(get_string('enrolledusers', 'enrol'), $parentnodes));
     $this->execute("behat_forms::press_button", get_string('enrolusers', 'enrol'));
     $this->execute('behat_forms::i_set_the_field_to', array(get_string('assignroles', 'role'), $rolename));
     if ($this->running_javascript()) {
         // We have a div here, not a tr.
         $userliteral = behat_context_helper::escape($userfullname);
         $userrowxpath = "//div[contains(concat(' ',normalize-space(@class),' '),' user ')][contains(., {$userliteral})]";
         $this->execute('behat_general::i_click_on_in_the', array(get_string('enrol', 'enrol'), "button", $userrowxpath, "xpath_element"));
         $this->execute("behat_forms::press_button", get_string('finishenrollingusers', 'enrol'));
     } else {
         $this->execute('behat_forms::i_set_the_field_to', array("addselect", $userfullname));
         $this->execute("behat_forms::press_button", "add");
     }
 }
Пример #14
0
 /**
  * Checks that the user has particular grade set by his reviewing peer in workshop
  *
  * @Then /^I should see grade "(?P<grade_string>[^"]*)" for workshop participant "(?P<participant_name_string>(?:[^"]|\\")*)" set by peer "(?P<reviewer_name_string>(?:[^"]|\\")*)"$/
  * @param string $grade
  * @param string $participant
  * @param string $reviewer
  */
 public function i_should_see_grade_for_workshop_participant_set_by_peer($grade, $participant, $reviewer)
 {
     $participantliteral = behat_context_helper::escape($participant);
     $reviewerliteral = behat_context_helper::escape($reviewer);
     $gradeliteral = behat_context_helper::escape($grade);
     $participantselector = "contains(concat(' ', normalize-space(@class), ' '), ' participant ') " . "and contains(.,{$participantliteral})";
     $trxpath = "//table/tbody/tr[td[{$participantselector}]]";
     $tdparticipantxpath = "//table/tbody/tr/td[{$participantselector}]";
     $tdxpath = "/td[contains(concat(' ', normalize-space(@class), ' '), ' receivedgrade ') and contains(.,{$reviewerliteral})]/" . "descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' grade ') and .={$gradeliteral}]";
     $tr = $this->find('xpath', $trxpath);
     $rowspan = $this->find('xpath', $tdparticipantxpath)->getAttribute('rowspan');
     $xpath = $trxpath . $tdxpath;
     if (!empty($rowspan)) {
         for ($i = 1; $i < $rowspan; $i++) {
             $xpath .= ' | ' . $trxpath . "/following-sibling::tr[{$i}]" . $tdxpath;
         }
     }
     $this->find('xpath', $xpath);
 }
Пример #15
0
 /**
  * Returns the xpath representing the selected criterion.
  *
  * It is the xpath when grading a rubric or viewing a rubric,
  * it is not the same xpath when editing a rubric.
  *
  * @param string $criterionname Literal including the criterion name.
  * @return string
  */
 protected function get_criterion_xpath($criterionname)
 {
     $literal = behat_context_helper::escape($criterionname);
     return "//tr[contains(concat(' ', normalize-space(@class), ' '), ' criterion ')]" . "[./descendant::td[@class='description'][text()={$literal}]]";
 }
Пример #16
0
 /**
  * Returns the opton XPath based on it's select xpath.
  *
  * @param string $option
  * @param string $selectxpath
  * @return string xpath
  */
 protected function get_option_xpath($option, $selectxpath)
 {
     $valueliteral = behat_context_helper::escape(trim($option));
     return $selectxpath . "/descendant::option[(./@value={$valueliteral} or normalize-space(.)={$valueliteral})]";
 }
Пример #17
0
 /**
  * Checks the provided value exists in specific row/column of table.
  *
  * @Then /^"(?P<row_string>[^"]*)" row "(?P<column_string>[^"]*)" column of "(?P<table_string>[^"]*)" table should contain "(?P<value_string>[^"]*)"$/
  * @throws ElementNotFoundException
  * @param string $row row text which will be looked in.
  * @param string $column column text to search (or numeric value for the column position)
  * @param string $table table id/class/caption
  * @param string $value text to check.
  */
 public function row_column_of_table_should_contain($row, $column, $table, $value)
 {
     $tablenode = $this->get_selected_node('table', $table);
     $tablexpath = $tablenode->getXpath();
     $rowliteral = behat_context_helper::escape($row);
     $valueliteral = behat_context_helper::escape($value);
     $columnliteral = behat_context_helper::escape($column);
     if (preg_match('/^-?(\\d+)-?$/', $column, $columnasnumber)) {
         // Column indicated as a number, just use it as position of the column.
         $columnpositionxpath = "/child::*[position() = {$columnasnumber[1]}]";
     } else {
         // Header can be in thead or tbody (first row), following xpath should work.
         $theadheaderxpath = "thead/tr[1]/th[(normalize-space(.)=" . $columnliteral . " or a[normalize-space(text())=" . $columnliteral . "] or div[normalize-space(text())=" . $columnliteral . "])]";
         $tbodyheaderxpath = "tbody/tr[1]/td[(normalize-space(.)=" . $columnliteral . " or a[normalize-space(text())=" . $columnliteral . "] or div[normalize-space(text())=" . $columnliteral . "])]";
         // Check if column exists.
         $columnheaderxpath = $tablexpath . "[" . $theadheaderxpath . " | " . $tbodyheaderxpath . "]";
         $columnheader = $this->getSession()->getDriver()->find($columnheaderxpath);
         if (empty($columnheader)) {
             $columnexceptionmsg = $column . '" in table "' . $table . '"';
             throw new ElementNotFoundException($this->getSession(), "\n{$columnheaderxpath}\n\n" . 'Column', null, $columnexceptionmsg);
         }
         // Following conditions were considered before finding column count.
         // 1. Table header can be in thead/tr/th or tbody/tr/td[1].
         // 2. First column can have th (Gradebook -> user report), so having lenient sibling check.
         $columnpositionxpath = "/child::*[position() = count(" . $tablexpath . "/" . $theadheaderxpath . "/preceding-sibling::*) + 1]";
     }
     // Check if value exists in specific row/column.
     // Get row xpath.
     // GoutteDriver uses DomCrawler\Crawler and it is making XPath relative to the current context, so use descendant.
     $rowxpath = $tablexpath . "/tbody/tr[descendant::th[normalize-space(.)=" . $rowliteral . "] | descendant::td[normalize-space(.)=" . $rowliteral . "]]";
     $columnvaluexpath = $rowxpath . $columnpositionxpath . "[contains(normalize-space(.)," . $valueliteral . ")]";
     // Looks for the requested node inside the container node.
     $coumnnode = $this->getSession()->getDriver()->find($columnvaluexpath);
     if (empty($coumnnode)) {
         $locatorexceptionmsg = $value . '" in "' . $row . '" row with column "' . $column;
         throw new ElementNotFoundException($this->getSession(), "\n{$columnvaluexpath}\n\n" . 'Column value', null, $locatorexceptionmsg);
     }
 }
    /**
     * Finds a page edit cog and select an item from it
     *
     * If the page edit cog is in the page header and the item is not found there, click "More..." link
     * and find the item on the course/frontpage administration page
     *
     * @param array $nodelist
     * @throws ElementNotFoundException
     */
    protected function select_from_administration_menu($nodelist) {
        // Find administration menu.
        if ($menuxpath = $this->find_header_administration_menu()) {
            $isheader = true;
        } else {
            $menuxpath = $this->find_page_administration_menu(true);
            $isheader = false;
        }

        $this->toggle_page_administration_menu($menuxpath);

        if (!$isheader || count($nodelist) == 1) {
            $lastnode = end($nodelist);
            $linkname = behat_context_helper::escape($lastnode);
            $link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[normalize-space(.)=' . $linkname . ']');
            if ($link) {
                $link->click();
                $this->wait_for_pending_js();
                return;
            }
        }

        if ($isheader) {
            // Course administration and Front page administration will have subnodes under "More...".
            $linkname = behat_context_helper::escape(get_string('morenavigationlinks'));
            $link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[normalize-space(.)=' . $linkname . ']');
            if ($link) {
                $link->click();
                $this->execute('behat_general::wait_until_the_page_is_ready');
                $this->select_on_administration_page($nodelist);
                return;
            }
        }

        throw new ElementNotFoundException($this->getSession(),
            'Link "' . join(' > ', $nodelist) . '" not found in the current page edit menu"');
    }
Пример #19
0
 /**
  * Sets a previously created grading form as the activity grading form.
  *
  * @Given /^I set "(?P<activity_name_string>(?:[^"]|\\")*)" activity to use "(?P<grading_form_template_string>(?:[^"]|\\")*)" grading form$/
  * @param string $activityname
  * @param string $templatename
  */
 public function i_set_activity_to_use_grading_form($activityname, $templatename)
 {
     $templateliteral = behat_context_helper::escape($templatename);
     $templatexpath = "//h2[@class='template-name'][contains(., {$templateliteral})]/" . "following-sibling::div[contains(concat(' ', normalize-space(@class), ' '), ' template-actions ')]";
     // Should work with both templates and own forms.
     $literaltemplate = behat_context_helper::escape(get_string('templatepick', 'grading'));
     $literalownform = behat_context_helper::escape(get_string('templatepickownform', 'grading'));
     $usetemplatexpath = "/a[./descendant::div[text()={$literaltemplate}]]|" . "/a[./descendant::div[text()={$literalownform}]]";
     $this->execute('behat_grading::i_go_to_advanced_grading_page', $this->escape($activityname));
     $this->execute('behat_general::click_link', $this->escape(get_string('manageactionclone', 'grading')));
     $this->execute('behat_forms::i_set_the_field_to', array(get_string('searchownforms', 'grading'), 1));
     $this->execute('behat_general::i_click_on_in_the', array(get_string('search'), "button", "region-main", "region"));
     $this->execute('behat_general::i_click_on_in_the', array($this->escape($usetemplatexpath), "xpath_element", $this->escape($templatexpath), "xpath_element"));
     $this->execute('behat_forms::press_button', get_string('continue'));
 }
Пример #20
0
 /**
  * Opens the filepicker modal window and selects the repository.
  *
  * @throws ExpectationException Thrown by behat_base::find
  * @param NodeElement $filemanagernode The filemanager or filepicker form element DOM node.
  * @param mixed $repositoryname The repo name.
  * @return void
  */
 protected function open_add_file_window($filemanagernode, $repositoryname)
 {
     $exception = new ExpectationException('No files can be added to the specified filemanager', $this->getSession());
     // We should deal with single-file and multiple-file filemanagers,
     // catching the exception thrown by behat_base::find() in case is not multiple
     try {
         // Looking for the add button inside the specified filemanager.
         $add = $this->find('css', 'div.fp-btn-add a', $exception, $filemanagernode);
     } catch (Exception $e) {
         // Otherwise should be a single-file filepicker form element.
         $add = $this->find('css', 'input.fp-btn-choose', $exception, $filemanagernode);
     }
     $this->ensure_node_is_visible($add);
     $add->click();
     // Wait for the default repository (if any) to load. This checks that
     // the relevant div exists and that it does not include the loading image.
     $this->ensure_element_exists("//div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" . "//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content ')]" . "[not(descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content-loading ')])]", 'xpath_element');
     // Getting the repository link and opening it.
     $repoexception = new ExpectationException('The "' . $repositoryname . '" repository has not been found', $this->getSession());
     // Avoid problems with both double and single quotes in the same string.
     $repositoryname = behat_context_helper::escape($repositoryname);
     // Here we don't need to look inside the selected element because there can only be one modal window.
     $repositorylink = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-area ')]" . "//descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-name ')]" . "[normalize-space(.)={$repositoryname}]", $repoexception);
     // Selecting the repo.
     $this->ensure_node_is_visible($repositorylink);
     if (!$repositorylink->getParent()->getParent()->hasClass('active')) {
         // If the repository link is active, then the repository is already loaded.
         // Clicking it while it's active causes issues, so only click it when it isn't (see MDL-51014).
         $repositorylink->click();
     }
 }
    public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) {

        $activity = $this->escape($activityname);
        $activityliteral = behat_context_helper::escape($activityname);

        $this->execute("behat_course::i_duplicate_activity", $activity);

        // Determine the future new activity xpath from the former one.
        $duplicatedxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]" .
            "[contains(., $activityliteral)]/following-sibling::li";
        $duplicatedactionsmenuxpath = $duplicatedxpath . "/descendant::a[@data-toggle='dropdown']";

        if ($this->running_javascript()) {
            // We wait until the AJAX request finishes and the section is visible again.
            $hiddenlightboxxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]" .
                "[contains(., $activityliteral)]" .
                "/ancestor::li[contains(concat(' ', normalize-space(@class), ' '), ' section ')]" .
                "/descendant::div[contains(concat(' ', @class, ' '), ' lightbox ')][contains(@style, 'display: none')]";

            $this->execute("behat_general::wait_until_exists",
                array($this->escape($hiddenlightboxxpath), "xpath_element")
            );

            // Close the original activity actions menu.
            $this->i_close_actions_menu($activity);

            // The next sibling of the former activity will be the duplicated one, so we click on it from it's xpath as, at
            // this point, it don't even exists in the DOM (the steps are executed when we return them).
            $this->execute('behat_general::i_click_on',
                array($this->escape($duplicatedactionsmenuxpath), "xpath_element")
            );
        }

        // We force the xpath as otherwise mink tries to interact with the former one.
        $this->execute('behat_general::i_click_on_in_the',
            array(get_string('editsettings'), "link", $this->escape($duplicatedxpath), "xpath_element")
        );

        $this->execute("behat_forms::i_set_the_following_fields_to_these_values", $data);
        $this->execute("behat_forms::press_button", get_string('savechangesandreturntocourse'));

    }
Пример #22
0
 /**
  * Selects the backup to restore.
  *
  * @throws ExpectationException
  * @param string $backupfilename
  * @return void
  */
 protected function select_backup($backupfilename)
 {
     // Using xpath as there are other restore links before this one.
     $exception = new ExpectationException('The "' . $backupfilename . '" backup file can not be found in this page', $this->getSession());
     // The argument should be converted to an xpath literal.
     $backupfilename = behat_context_helper::escape($backupfilename);
     $xpath = "//tr[contains(., {$backupfilename})]/descendant::a[contains(., '" . get_string('restore') . "')]";
     $restorelink = $this->find('xpath', $xpath, $exception);
     $restorelink->click();
     // Confirm the backup contents.
     $this->find_button(get_string('continue'))->press();
 }
    public function i_reset_weights_for_grade_category($gradeitem) {

        $steps = array();

        if ($this->running_javascript()) {
            $gradeitemliteral = behat_context_helper::escape($gradeitem);
            $xpath = "//tr[contains(.,$gradeitemliteral)]//*[contains(@class,'moodle-actionmenu')]";
            if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
                $xpath = "//tr[contains(.,$gradeitemliteral)]";
                $this->execute("behat_action_menu::i_open_the_action_menu_in", array($xpath, "xpath_element"));
            }
        }

        $linktext = get_string('resetweights', 'grades', (object)array('itemname' => $gradeitem));
        $this->execute("behat_general::i_click_on", array($this->escape($linktext), "link"));
    }
Пример #24
0
 /**
  * Finds DOM nodes in the page using named selectors.
  *
  * The point of using this method instead of Mink ones is the spin
  * method of behat_base::find() that looks for the element until it
  * is available or it timeouts, this avoids the false failures received
  * when selenium tries to execute commands on elements that are not
  * ready to be used.
  *
  * All steps that requires elements to be available before interact with
  * them should use one of the find* methods.
  *
  * The methods calls requires a {'find_' . $elementtype}($locator)
  * format, like find_link($locator), find_select($locator),
  * find_button($locator)...
  *
  * @link http://mink.behat.org/#named-selectors
  * @throws coding_exception
  * @param string $name The name of the called method
  * @param mixed $arguments
  * @return NodeElement
  */
 public function __call($name, $arguments)
 {
     if (substr($name, 0, 5) !== 'find_') {
         throw new coding_exception('The "' . $name . '" method does not exist');
     }
     // Only the named selector identifier.
     $cleanname = substr($name, 5);
     // All named selectors shares the interface.
     if (count($arguments) !== 1) {
         throw new coding_exception('The "' . $cleanname . '" named selector needs the locator as it\'s single argument');
     }
     // Redirecting execution to the find method with the specified selector.
     // It will detect if it's pointing to an unexisting named selector.
     return $this->find('named_partial', array($cleanname, behat_context_helper::escape($arguments[0])));
 }
Пример #25
0
 /**
  * Helper function to get sub-navigation node.
  *
  * @throws ExpectationException if note not found.
  * @param string $nodetext node to find.
  * @param NodeElement $parentnode parent navigation node.
  * @return NodeElement.
  */
 protected function get_navigation_node($nodetext, $parentnode = null)
 {
     // Avoid problems with quotes.
     $nodetextliteral = behat_context_helper::escape($nodetext);
     $xpath = "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" . "[child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" . "/child::span[normalize-space(.)=" . $nodetextliteral . "]]";
     $node = $parentnode->find('xpath', $xpath);
     if (!$node) {
         $xpath = "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" . "[child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" . "/child::a[normalize-space(.)=" . $nodetextliteral . "]]";
         $node = $parentnode->find('xpath', $xpath);
     }
     if (!$node) {
         throw new ExpectationException('Sub-navigation node "' . $nodetext . '" not found under "' . $parentnode->getText() . '"', $this->getSession());
     }
     return $node;
 }
Пример #26
0
 /**
  * Go to the course participants
  *
  * @Given /^I navigate to course participants$/
  */
 public function i_navigate_to_course_participants()
 {
     $coursestr = behat_context_helper::escape(get_string('courses'));
     $mycoursestr = behat_context_helper::escape(get_string('mycourses'));
     $xpath = "//div[contains(@class,'block')]//li[p/*[string(.)={$coursestr} or string(.)={$mycoursestr}]]";
     $this->execute('behat_general::i_click_on_in_the', [get_string('participants'), 'link', $xpath, 'xpath_element']);
 }
Пример #27
0
 /**
  * Checks grade values with or without a edit box.
  *
  * @Then /^the grade for "([^"]*)" in grade item "([^"]*)" should match "([^"]*)"$/
  * @throws Exception
  * @throws ElementNotFoundException
  * @param string $student
  * @param string $itemname
  * @param string $value
  */
 public function the_grade_should_match($student, $itemname, $value)
 {
     $xpath = $this->get_student_and_grade_value_selector($student, $itemname);
     $gradefield = $this->getSession()->getPage()->find('xpath', $xpath);
     if (!empty($gradefield)) {
         // Get the field.
         $fieldtype = behat_field_manager::guess_field_type($gradefield, $this->getSession());
         if (!$fieldtype) {
             throw new Exception('Could not get field type for grade field "' . $itemname . '"');
         }
         $field = behat_field_manager::get_field_instance($fieldtype, $gradefield, $this->getSession());
         if (!$field->matches($value)) {
             $fieldvalue = $field->get_value();
             throw new ExpectationException('The "' . $student . '" and "' . $itemname . '" grade is "' . $fieldvalue . '", "' . $value . '" expected', $this->getSession());
         }
     } else {
         // If there isn't a form field, just search for contents.
         $valueliteral = behat_context_helper::escape($value);
         $xpath = $this->get_student_and_grade_cell_selector($student, $itemname);
         $xpath .= "[contains(normalize-space(.)," . $valueliteral . ")]";
         $node = $this->getSession()->getDriver()->find($xpath);
         if (empty($node)) {
             $locatorexceptionmsg = 'Cell for "' . $student . '" and "' . $itemname . '" with value "' . $value . '"';
             throw new ElementNotFoundException($this->getSession(), $locatorexceptionmsg, null, $xpath);
         }
     }
 }
Пример #28
0
 /**
  * Clicks to expand or collapse a category displayed on the frontpage
  *
  * @Given /^I toggle "(?P<categoryname_string>(?:[^"]|\\")*)" category children visibility in frontpage$/
  * @throws ExpectationException
  * @param string $categoryname
  */
 public function i_toggle_category_children_visibility_in_frontpage($categoryname)
 {
     $headingtags = array();
     for ($i = 1; $i <= 6; $i++) {
         $headingtags[] = 'self::h' . $i;
     }
     $exception = new ExpectationException('"' . $categoryname . '" category can not be found', $this->getSession());
     $categoryliteral = behat_context_helper::escape($categoryname);
     $xpath = "//div[@class='info']/descendant::*[" . implode(' or ', $headingtags) . "][@class='categoryname'][./descendant::a[.={$categoryliteral}]]";
     $node = $this->find('xpath', $xpath, $exception);
     $node->click();
     // Smooth expansion.
     $this->getSession()->wait(1000, false);
 }