diff --git a/blocks/tests/behat/behat_blocks.php b/blocks/tests/behat/behat_blocks.php index c90c6972f9a..a5a1652e00e 100644 --- a/blocks/tests/behat/behat_blocks.php +++ b/blocks/tests/behat/behat_blocks.php @@ -25,6 +25,8 @@ // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. +use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException; + require_once(__DIR__ . '/../../../lib/behat/behat_base.php'); /** @@ -56,6 +58,20 @@ class behat_blocks extends behat_base { } } + /** + * Adds the selected block if it is not already present. Editing mode must be previously enabled. + * + * @Given /^I add the "(?P(?:[^"]|\\")*)" block if not present$/ + * @param string $blockname + */ + public function i_add_the_block_if_not_present($blockname) { + try { + $this->get_text_selector_node('block', $blockname); + } catch (ElementNotFoundException $e) { + $this->execute('behat_blocks::i_add_the_block', [$blockname]); + } + } + /** * Docks a block. Editing mode should be previously enabled. * diff --git a/course/tests/behat/behat_course.php b/course/tests/behat/behat_course.php index 759b3427791..df95cce26ff 100644 --- a/course/tests/behat/behat_course.php +++ b/course/tests/behat/behat_course.php @@ -51,7 +51,7 @@ class behat_course extends behat_base { try { $this->execute("behat_forms::press_button", get_string('turneditingon')); } catch (Exception $e) { - $this->execute("behat_general::i_click_on_in_the", [get_string('turneditingon'), 'link', 'Administration', 'block']); + $this->execute("behat_navigation::i_navigate_to_in_current_page_administration", [get_string('turneditingon')]); } } @@ -64,7 +64,7 @@ class behat_course extends behat_base { try { $this->execute("behat_forms::press_button", get_string('turneditingoff')); } catch (Exception $e) { - $this->execute("behat_general::i_click_on_in_the", [get_string('turneditingoff'), 'link', 'Administration', 'block']); + $this->execute("behat_navigation::i_navigate_to_in_current_page_administration", [get_string('turneditingoff')]); } } @@ -1728,4 +1728,16 @@ class behat_course extends behat_base { $node = $this->get_management_category_listing_node_by_name($name); $node->find('css', 'a.categoryname')->click(); } + + /** + * 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']); + } } diff --git a/grade/grading/tests/behat/behat_grading.php b/grade/grading/tests/behat/behat_grading.php index c4c9307e530..2aa49bc5a37 100644 --- a/grade/grading/tests/behat/behat_grading.php +++ b/grade/grading/tests/behat/behat_grading.php @@ -49,13 +49,8 @@ class behat_grading extends behat_base { $this->execute('behat_general::click_link', $this->escape($activityname)); - $this->execute('behat_general::i_click_on_in_the', - array( - get_string('gradingmanagement', 'grading'), - 'link', - 'Administration', - 'block' - )); + $this->execute('behat_navigation::i_navigate_to_in_current_page_administration', + get_string('gradingmanagement', 'grading')); } /** @@ -92,13 +87,8 @@ class behat_grading extends behat_base { $this->execute('behat_general::click_link', $this->escape($activityname)); - $this->execute('behat_general::i_click_on_in_the', - array( - get_string('viewgrading', 'mod_assign'), - 'link', - 'Administration', - 'block' - )); + $this->execute('behat_navigation::i_navigate_to_in_current_page_administration', + get_string('viewgrading', 'mod_assign')); $this->execute('behat_general::i_click_on_in_the', array( @@ -169,13 +159,8 @@ class behat_grading extends behat_base { $this->execute('behat_forms::press_button', 'Ok'); $this->execute('behat_general::i_click_on', array($this->escape(get_string('editsettings')), 'link')); $this->execute('behat_forms::press_button', get_string('cancel')); - $this->execute('behat_general::i_click_on_in_the', - array( - get_string('viewgrading', 'mod_assign'), - 'link', - 'Administration', - 'block' - )); + $this->execute('behat_navigation::i_navigate_to_in_current_page_administration', + get_string('viewgrading', 'mod_assign')); } /** diff --git a/grade/tests/behat/behat_grade.php b/grade/tests/behat/behat_grade.php index 787af0db4a2..4a1bbe9193b 100644 --- a/grade/tests/behat/behat_grade.php +++ b/grade/tests/behat/behat_grade.php @@ -247,30 +247,17 @@ class behat_grade extends behat_base { } /** - * Navigates to the course gradebook and selects a specified item from the grade navigation tabs. + * Select the tab in the gradebook. We must be on one of the gradebook pages already. * - * Examples: - * - I go to "Setup > Gradebook setup" in the course gradebook - * - I go to "Scales" in the course gradebook - * - I go to "Letters > View" in the course gradebook - * - I go to "View > User report" in the course gradebook // for teachers - * - I go to "User report" in the course gradebook // for students - * - * @Given /^I go to "(?P(?:[^"]|\\")*)" in the course gradebook$/ - * @param string $gradepath + * @param string $gradepath examples: "View > User report", "Letters > View", "Scales" */ - public function i_go_to_in_the_course_gradebook($gradepath) { + protected function select_in_gradebook_tabs($gradepath) { $gradepath = preg_split('/\s*>\s*/', trim($gradepath)); if (count($gradepath) > 2) { - throw new DriverException('Grade path is too long (must have no more than two items separated with ">")'); + throw new coding_exception('Grade path is too long (must have no more than two items separated with ">")'); } - // If we are not on one of the gradebook pages already, follow "Grades" link in the navigation block. $xpath = '//div[contains(@class,\'grade-navigation\')]'; - if (!$this->getSession()->getPage()->findAll('xpath', $xpath)) { - $this->execute("behat_general::i_click_on_in_the", array(get_string('grades'), 'link', - get_string('pluginname', 'block_navigation'), 'block')); - } // If the first row of the grade-navigation tabs does not have $gradepath[0] as active tab, click on it. $link = '\'' . $this->escape($gradepath[0]) . '\''; @@ -290,4 +277,40 @@ class behat_grade extends behat_base { } } } + + /** + * Navigates to the course gradebook and selects a specified item from the grade navigation tabs. + * + * Examples: + * - I navigate to "Setup > Gradebook setup" in the course gradebook + * - I navigate to "Scales" in the course gradebook + * - I navigate to "Letters > View" in the course gradebook + * - I navigate to "View > User report" in the course gradebook // for teachers + * - I navigate to "User report" in the course gradebook // for students + * + * @Given /^I navigate to "(?P(?:[^"]|\\")*)" in the course gradebook$/ + * @param string $gradepath + */ + public function i_navigate_to_in_the_course_gradebook($gradepath) { + // If we are not on one of the gradebook pages already, follow "Grades" link in the navigation block. + $xpath = '//div[contains(@class,\'grade-navigation\')]'; + if (!$this->getSession()->getPage()->findAll('xpath', $xpath)) { + $this->execute("behat_general::i_click_on_in_the", array(get_string('grades'), 'link', + get_string('pluginname', 'block_navigation'), 'block')); + } + + $this->select_in_gradebook_tabs($gradepath); + } + + /** + * Navigates to the course gradebook and selects a specified item from the grade navigation tabs. + * + * @todo MDL-57282 deprecate in Moodle 3.3 + * + * @Given /^I go to "(?P(?:[^"]|\\")*)" in the course gradebook$/ + * @param string $gradepath + */ + public function i_go_to_in_the_course_gradebook($gradepath) { + $this->execute('behat_grade::i_navigate_to_in_the_course_gradebook', $gradepath); + } } diff --git a/lib/blocklib.php b/lib/blocklib.php index 2baca98e5e5..e3a386883ea 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -387,10 +387,7 @@ class block_manager { $requiredbythemeblocks = $PAGE->theme->requiredblocks; } - // We need blocks for behat, till MDL-56614 gets in. - if (defined('BEHAT_SITE_RUNNING')) { - return array('navigation', 'settings'); - } else if ($requiredbythemeblocks === false) { + if ($requiredbythemeblocks === false) { return array('navigation', 'settings'); } else if ($requiredbythemeblocks === '') { return array(); diff --git a/lib/tests/behat/behat_navigation.php b/lib/tests/behat/behat_navigation.php index f4ae59a0b9c..fff55ffc4b8 100644 --- a/lib/tests/behat/behat_navigation.php +++ b/lib/tests/behat/behat_navigation.php @@ -225,18 +225,37 @@ class behat_navigation extends behat_base { * * @Given /^I navigate to "(?P(?:[^"]|\\")*)" node in "(?P(?:[^"]|\\")*)"$/ * + * @todo MDL-57281 deprecate in Moodle 3.1 + * * @throws ExpectationException * @param string $nodetext navigation node to click. * @param string $parentnodes comma seperated list of parent nodes. * @return void */ public function i_navigate_to_node_in($nodetext, $parentnodes) { + // This step needs to be deprecated and replaced with one of: + // - I navigate to "PATH" in current page administration + // - I navigate to "PATH" in site administration + // - I navigate to course participants + // - I navigate to "PATH" in the course gradebook + // - I click on "LINK" "link" in the "Navigation" "block" . + $parentnodes = array_map('trim', explode('>', $parentnodes)); + $this->select_node_in_navigation($nodetext, $parentnodes); + } + + /** + * Finds a node in the Navigation or Administration tree and clicks on it. + * + * @param string $nodetext + * @param array $parentnodes + * @throws ExpectationException + */ + protected function select_node_in_navigation($nodetext, $parentnodes) { // Site admin is different and needs special treatment. $siteadminstr = get_string('administrationsite'); // Create array of all parentnodes. - $parentnodes = array_map('trim', explode('>', $parentnodes)); $countparentnode = count($parentnodes); // If JS is disabled and Site administration is not expanded we @@ -415,4 +434,92 @@ class behat_navigation extends behat_base { $this->execute('behat_general::i_click_on', array(".btn-navbar", "css_element")); } + + /** + * Go to current page setting item + * + * This can be used on front page, course, category or modules pages. + * + * @Given /^I navigate to "(?P(?:[^"]|\\")*)" in current page administration$/ + * + * @throws ExpectationException + * @param string $nodetext navigation node to click, may contain path, for example "Reports > Overview" + * @return void + */ + public function i_navigate_to_in_current_page_administration($nodetext) { + $parentnodes = array_map('trim', explode('>', $nodetext)); + // Find the name of the first category of the administration block tree. + $xpath = '//div[contains(@class,\'block_settings\')]//div[@id=\'settingsnav\']/ul/li[1]/p[1]/span'; + $node = $this->find('xpath', $xpath); + array_unshift($parentnodes, $node->getText()); + $lastnode = array_pop($parentnodes); + $this->select_node_in_navigation($lastnode, $parentnodes); + } + + /** + * Checks that current page administration contains text + * + * @Given /^"(?P(?:[^"]|\\")*)" "(?P[^"]*)" should exist in current page administration$/ + * + * @throws ExpectationException + * @param string $element The locator of the specified selector. + * This may be a path, for example "Subscription mode > Forced subscription" + * @param string $selectortype The selector type + * @return void + */ + public function should_exist_in_current_page_administration($element, $selectortype) { + $parentnodes = array_map('trim', explode('>', $element)); + $element = array_pop($parentnodes); + + foreach ($parentnodes as $parentnode) { + try { + $this->i_expand_node($parentnode); + } catch (ExpectationException $e) { + // Parent node not found. + return; + } + } + + $xpath = '//div[contains(@class,\'block_settings\')]//div[@id=\'settingsnav\']/ul/li[1]'; + $this->execute('behat_general::should_exist_in_the', [$element, $selectortype, $xpath, 'xpath_element']); + } + + /** + * Checks that current page administration contains text + * + * @Given /^"(?P(?:[^"]|\\")*)" "(?P[^"]*)" should not exist in current page administration$/ + * + * @throws ExpectationException + * @param string $element The locator of the specified selector. + * This may be a path, for example "Subscription mode > Forced subscription" + * @param string $selectortype The selector type + * @return void + */ + public function should_not_exist_in_current_page_administration($element, $selectortype) { + $parentnodes = array_map('trim', explode('>', $element)); + $element = array_pop($parentnodes); + + foreach ($parentnodes as $parentnode) { + $this->i_expand_node($parentnode); + } + + $xpath = '//div[contains(@class,\'block_settings\')]//div[@id=\'settingsnav\']/ul/li[1]'; + $this->execute('behat_general::should_not_exist_in_the', [$element, $selectortype, $xpath, 'xpath_element']); + } + + /** + * Go to site administration item + * + * @Given /^I navigate to "(?P(?:[^"]|\\")*)" in site administration$/ + * + * @throws ExpectationException + * @param string $nodetext navigation node to click, may contain path, for example "Reports > Overview" + * @return void + */ + public function i_navigate_to_in_site_administration($nodetext) { + $parentnodes = array_map('trim', explode('>', $nodetext)); + array_unshift($parentnodes, get_string('administrationsite')); + $lastnode = array_pop($parentnodes); + $this->select_node_in_navigation($lastnode, $parentnodes); + } } diff --git a/mod/data/tests/behat/behat_mod_data.php b/mod/data/tests/behat/behat_mod_data.php index da2abdd06dd..5d0d34d7a21 100644 --- a/mod/data/tests/behat/behat_mod_data.php +++ b/mod/data/tests/behat/behat_mod_data.php @@ -50,8 +50,14 @@ class behat_mod_data extends behat_base { public function i_add_a_field_to_database_and_i_fill_the_form_with($fieldtype, $activityname, TableNode $fielddata) { $this->execute("behat_general::click_link", $this->escape($activityname)); - $this->execute("behat_navigation::i_navigate_to_node_in", array(get_string('fields', 'mod_data'), - get_string('pluginadministration', 'mod_data'))); + + // Open "Fields" tab if it is not already open. + $fieldsstr = get_string('fields', 'mod_data'); + $xpath = '//ul[contains(@class,\'nav-tabs\')]//*[contains(@class,\'active\') and contains(normalize-space(.), \'' . + $fieldsstr . '\')]'; + if (!$this->getSession()->getPage()->findAll('xpath', $xpath)) { + $this->execute("behat_general::i_click_on_in_the", array($fieldsstr, 'link', '.nav-tabs', 'css_element')); + } $this->execute('behat_forms::i_set_the_field_to', array('newtype', $this->escape($fieldtype))); diff --git a/mod/workshop/allocation/manual/tests/behat/behat_workshopallocation_manual.php b/mod/workshop/allocation/manual/tests/behat/behat_workshopallocation_manual.php index 7427dc60800..a4d09645853 100644 --- a/mod/workshop/allocation/manual/tests/behat/behat_workshopallocation_manual.php +++ b/mod/workshop/allocation/manual/tests/behat/behat_workshopallocation_manual.php @@ -90,13 +90,7 @@ class behat_workshopallocation_manual extends behat_base { public function i_allocate_submissions_in_workshop_as($workshopname, TableNode $table) { $this->find_link($workshopname)->click(); - $this->execute('behat_general::i_click_on_in_the', - array( - get_string('allocate', 'workshop'), - 'link', - 'Administration', - 'block' - )); + $this->execute('behat_navigation::i_navigate_to_in_current_page_administration', get_string('allocate', 'workshop')); $rows = $table->getRows(); $reviewer = $participant = null; for ($i = 0; $i < count($rows[0]); $i++) { diff --git a/mod/workshop/tests/behat/behat_mod_workshop.php b/mod/workshop/tests/behat/behat_mod_workshop.php index e36c604890c..603d31b5eae 100644 --- a/mod/workshop/tests/behat/behat_mod_workshop.php +++ b/mod/workshop/tests/behat/behat_mod_workshop.php @@ -90,23 +90,14 @@ class behat_mod_workshop extends behat_base { * @param TableNode $table data to fill the submission form with, must contain 'Title' */ public function i_edit_assessment_form_in_workshop_as($workshopname, $table) { - $workshopname = $this->escape($workshopname); - $editassessmentform = $this->escape(get_string('editassessmentform', 'workshop')); - $saveandclose = $this->escape(get_string('saveandclose', 'workshop')); - $this->execute('behat_general::click_link', $workshopname); - $this->execute('behat_general::i_click_on_in_the', - array( - $editassessmentform, - 'link', - 'Administration', - 'block' - )); + $this->execute('behat_navigation::i_navigate_to_in_current_page_administration', + get_string('editassessmentform', 'workshop')); $this->execute("behat_forms::i_set_the_following_fields_to_these_values", $table); - $this->execute("behat_forms::press_button", $saveandclose); + $this->execute("behat_forms::press_button", get_string('saveandclose', 'workshop')); } /** diff --git a/theme/boost/layout/columns2.php b/theme/boost/layout/columns2.php index e0207faa3bc..d942fcbabba 100644 --- a/theme/boost/layout/columns2.php +++ b/theme/boost/layout/columns2.php @@ -27,7 +27,7 @@ defined('MOODLE_INTERNAL') || die(); user_preference_allow_ajax_update('drawer-open-nav', PARAM_ALPHA); require_once($CFG->libdir . '/behat/lib.php'); -if (isloggedin() && !behat_is_test_site()) { +if (isloggedin()) { $navdraweropen = (get_user_preferences('drawer-open-nav', 'true') == 'true'); } else { $navdraweropen = false; diff --git a/theme/boost/scss/moodle/debug.scss b/theme/boost/scss/moodle/debug.scss index 46abbf14e35..1ee0fb8ffec 100644 --- a/theme/boost/scss/moodle/debug.scss +++ b/theme/boost/scss/moodle/debug.scss @@ -23,6 +23,7 @@ body.behat-site { -webkit-transition: initial; -moz-transition: initial; transition: initial; + position: absolute; } } diff --git a/theme/boost/tests/behat/behat_theme_boost_behat_admin.php b/theme/boost/tests/behat/behat_theme_boost_behat_admin.php index 018a3fc3429..21ca9d7088e 100644 --- a/theme/boost/tests/behat/behat_theme_boost_behat_admin.php +++ b/theme/boost/tests/behat/behat_theme_boost_behat_admin.php @@ -45,16 +45,12 @@ class behat_theme_boost_behat_admin extends behat_admin { 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); - } + $this->execute('behat_navigation::i_select_from_flat_navigation_drawer', [get_string('administrationsite')]); // Search by label. - $searchbox = $this->find_field(get_string('searchinsettings', 'admin')); + $searchbox = $this->find_field(get_string('query', 'admin')); $searchbox->setValue($label); - $submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]'); + $submitsearch = $this->find('css', 'form input[type=submit][name=search]'); $submitsearch->press(); $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); diff --git a/theme/boost/tests/behat/behat_theme_boost_behat_course.php b/theme/boost/tests/behat/behat_theme_boost_behat_course.php index 58fd4017c3c..64a7c597549 100644 --- a/theme/boost/tests/behat/behat_theme_boost_behat_course.php +++ b/theme/boost/tests/behat/behat_theme_boost_behat_course.php @@ -258,4 +258,8 @@ class behat_theme_boost_behat_course extends behat_course { return true; } + + public function i_navigate_to_course_participants() { + $this->execute('behat_navigation::i_select_from_flat_navigation_drawer', get_string('participants')); + } } diff --git a/theme/boost/tests/behat/behat_theme_boost_behat_grade.php b/theme/boost/tests/behat/behat_theme_boost_behat_grade.php index 44df7038b46..1820f2cbc89 100644 --- a/theme/boost/tests/behat/behat_theme_boost_behat_grade.php +++ b/theme/boost/tests/behat/behat_theme_boost_behat_grade.php @@ -145,4 +145,14 @@ class behat_theme_boost_behat_grade extends behat_grade { $linktext = get_string('resetweights', 'grades', (object)array('itemname' => $gradeitem)); $this->execute("behat_general::i_click_on", array($this->escape($linktext), "link")); } + + public function i_navigate_to_in_the_course_gradebook($gradepath) { + // If we are not on one of the gradebook pages already, follow "Grades" link in the navigation drawer. + $xpath = '//div[contains(@class,\'grade-navigation\')]'; + if (!$this->getSession()->getPage()->findAll('xpath', $xpath)) { + $this->execute('behat_navigation::i_select_from_flat_navigation_drawer', get_string('grades')); + } + + $this->select_in_gradebook_tabs($gradepath); + } } diff --git a/theme/boost/tests/behat/behat_theme_boost_behat_navigation.php b/theme/boost/tests/behat/behat_theme_boost_behat_navigation.php index 2f64866b32f..7db070e813a 100644 --- a/theme/boost/tests/behat/behat_theme_boost_behat_navigation.php +++ b/theme/boost/tests/behat/behat_theme_boost_behat_navigation.php @@ -26,7 +26,7 @@ require_once(__DIR__ . '/../../../../lib/tests/behat/behat_navigation.php'); use Behat\Mink\Exception\ExpectationException as ExpectationException; -use Behat\Mink\Exception\DriverException as DriverException; +use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException; /** * Steps definitions to navigate through the navigation tree nodes (overrides). @@ -129,4 +129,228 @@ class behat_theme_boost_behat_navigation extends behat_navigation { $this->i_open_flat_navigation_drawer(); $this->execute('behat_general::i_click_on_in_the', [$link, 'link', '#nav-drawer', 'css_element']); } + + /** + * If we are not on the course main page, click on the course link in the navbar + */ + protected function go_to_main_course_page() { + $starturl = rtrim($this->getMinkParameter('base_url'), '/') . '/'; + $url = $this->getSession()->getCurrentUrl(); + if (strpos($url, $starturl) === 0) { + $url = substr($url, strlen($starturl)); + } + if (!preg_match('|^course/view.php?id=[\d]+|', $url)) { + $this->find('xpath', '//header//div[@id=\'page-navbar\']//a[contains(@href,\'/course/view.php?id=\')]')->click(); + } + } + + /** + * Finds and clicks a link on the admin page (site administration or course administration) + * + * @param array $nodelist + */ + protected function select_on_administration_page($nodelist) { + $parentnodes = $nodelist; + $lastnode = array_pop($parentnodes); + $xpath = '//section[@id=\'region-main\']'; + + // Check if there is a separate tab for this submenu of the page. If found go to it. + if ($parentnodes) { + $tabname = behat_context_helper::escape($parentnodes[0]); + $tabxpath = '//ul[@role=\'tablist\']/li/a[normalize-space(.)=' . $tabname . ']'; + if ($node = $this->getSession()->getPage()->find('xpath', $tabxpath)) { + if ($this->running_javascript()) { + // Click on the tab and add 'active' tab to the xpath. + $node->click(); + $xpath .= '//div[contains(@class,\'active\')]'; + } else { + // Add the tab content selector to the xpath. + $tabid = behat_context_helper::escape(ltrim($node->getAttribute('href'), '#')); + $xpath .= '//div[@id = ' . $tabid . ']'; + } + array_shift($parentnodes); + } + } + + // Find a section with the parent name in it. + if ($parentnodes) { + // Find the section on the page (links may be repeating in different sections). + $section = behat_context_helper::escape($parentnodes[0]); + $xpath .= '//div[@class=\'row\' and contains(.,'.$section.')]'; + } + + // Find a link and click on it. + $linkname = behat_context_helper::escape($lastnode); + $xpath .= '//a[normalize-space(.)=' . $linkname . ']'; + if (!$node = $this->getSession()->getPage()->find('xpath', $xpath)) { + throw new ElementNotFoundException($this->getSession(), 'Link "' . join(' > ', $nodelist) . '"" not found on the page'); + } + $node->click(); + $this->wait_for_pending_js(); + } + + /** + * Locates the administration menu in the
element and returns its xpath + * + * @param bool $mustexist if specified throws an exception if menu is not found + * @return null|string + */ + protected function find_header_administration_menu($mustexist = false) { + $menuxpath = '//header[@id=\'page-header\']//div[contains(@class,\'moodle-actionmenu\')]'; + if ($mustexist) { + $exception = new ElementNotFoundException($this->getSession(), 'Page header administration menu is not found'); + $this->find('xpath', $menuxpath, $exception); + } else if (!$this->getSession()->getPage()->find('xpath', $menuxpath)) { + return null; + } + return $menuxpath; + } + + /** + * Locates the administration menu on the page (but not in the header) and returns its xpath + * + * @param bool $mustexist if specified throws an exception if menu is not found + * @return null|string + */ + protected function find_page_administration_menu($mustexist = false) { + $menuxpath = '//div[@id=\'region-main-settings-menu\']'; + if ($mustexist) { + $exception = new ElementNotFoundException($this->getSession(), 'Page administration menu is not found'); + $this->find('xpath', $menuxpath, $exception); + } else if (!$this->getSession()->getPage()->find('xpath', $menuxpath)) { + return null; + } + return $menuxpath; + } + + /** + * Toggles administration menu + * + * @param string $menuxpath (optional) xpath to the page administration menu if already known + */ + protected function toggle_page_administration_menu($menuxpath = null) { + if (!$menuxpath) { + $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(); + } + if ($menuxpath && $this->running_javascript()) { + $this->find('xpath', $menuxpath . '//a[@data-toggle=\'dropdown\']')->click(); + $this->wait_for_pending_js(); + } + } + + /** + * 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"'); + } + + public function should_exist_in_current_page_administration($element, $selectortype) { + $nodes = array_map('trim', explode('>', $element)); + $nodetext = end($nodes); + + // Find administration menu. + $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(true); + + $this->toggle_page_administration_menu($menuxpath); + $this->execute('behat_general::should_exist_in_the', [$nodetext, $selectortype, $menuxpath, 'xpath_element']); + $this->toggle_page_administration_menu($menuxpath); + } + + public function should_not_exist_in_current_page_administration($element, $selectortype) { + $nodes = array_map('trim', explode('>', $element)); + $nodetext = end($nodes); + + // Find administration menu. + $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(); + if (!$menuxpath) { + // Menu not found, exit. + return; + } + + $this->toggle_page_administration_menu($menuxpath); + $this->execute('behat_general::should_not_exist_in_the', [$nodetext, $selectortype, $menuxpath, 'xpath_element']); + $this->toggle_page_administration_menu($menuxpath); + } + + public function i_navigate_to_node_in($nodetext, $parentnodes) { + $parentnodes = array_map('trim', explode('>', $parentnodes)); + $nodelist = array_merge($parentnodes, [$nodetext]); + $firstnode = array_shift($nodelist); + + if ($firstnode === get_string('administrationsite')) { + $this->i_select_from_flat_navigation_drawer(get_string('administrationsite')); + $this->select_on_administration_page($nodelist); + return; + } + + if ($firstnode === get_string('sitepages')) { + if ($nodetext === get_string('calendar', 'calendar')) { + $this->i_select_from_flat_navigation_drawer($nodetext); + } else { + // TODO MDL-57120 other links under "Site pages" are not accessible without navigation block. + $this->select_node_in_navigation($nodetext, $parentnodes); + } + return; + } + + if ($firstnode === get_string('courseadministration')) { + // Administration menu is available only on the main course page where settings in Administration + // block (original purpose of the step) are available on every course page. + $this->go_to_main_course_page(); + } + + $this->select_from_administration_menu($nodelist); + } + + public function i_navigate_to_in_current_page_administration($nodetext) { + $nodelist = array_map('trim', explode('>', $nodetext)); + $this->select_from_administration_menu($nodelist); + } + + public function i_navigate_to_in_site_administration($nodetext) { + $nodelist = array_map('trim', explode('>', $nodetext)); + $this->i_select_from_flat_navigation_drawer(get_string('administrationsite')); + $this->select_on_administration_page($nodelist); + } }