MDL-56511 theme_boost: Fixing minor behat failures
[moodle.git] / theme / boost / tests / behat / behat_theme_boost_behat_navigation.php
CommitLineData
63e4df60
DW
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Navigation steps overrides.
19 *
20 * @copyright 2016 Damyon Wiese
21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 */
23
24// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
25
26require_once(__DIR__ . '/../../../../lib/tests/behat/behat_navigation.php');
27
28use Behat\Mink\Exception\ExpectationException as ExpectationException;
ebcff7e2 29use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
63e4df60
DW
30
31/**
32 * Steps definitions to navigate through the navigation tree nodes (overrides).
33 *
34 * @copyright 2016 Damyon Wiese
35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 */
2ede86d7 37class behat_theme_boost_behat_navigation extends behat_navigation {
63e4df60
DW
38
39 public function i_follow_in_the_user_menu($nodetext) {
40
41 if ($this->running_javascript()) {
42 // The user menu must be expanded when JS is enabled.
f5779bb1 43 $xpath = "//div[contains(concat(' ', @class, ' '), ' usermenu ')]//a[contains(concat(' ', @class, ' '), ' dropdown-toggle ')]";
63e4df60
DW
44 $this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
45 }
46
47 // Now select the link.
48 // The CSS path is always present, with or without JS.
49 $csspath = ".usermenu .dropdown-menu";
50
51 $this->execute('behat_general::i_click_on_in_the',
52 array($nodetext, "link", $csspath, "css_element")
53 );
54 }
55
56 protected function get_top_navigation_node($nodetext) {
57
58 // Avoid problems with quotes.
59 $nodetextliteral = behat_context_helper::escape($nodetext);
60 $exception = new ExpectationException('Top navigation node "' . $nodetext . ' not found in "', $this->getSession());
61
62 // First find in navigation block.
63 $xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' card-text ')]" .
64 "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
65 "/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" .
66 "/ul/li[contains(concat(' ', normalize-space(@class), ' '), ' contains_branch ')]" .
67 "[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
8857c715 68 "/*[contains(normalize-space(.), " . $nodetextliteral .")]]" .
63e4df60
DW
69 "|" .
70 "//div[contains(concat(' ', normalize-space(@class), ' '), ' card-text ')]/div" .
71 "/ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
72 "/li[p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
8857c715 73 "/*[contains(normalize-space(.), " . $nodetextliteral .")]]";
63e4df60
DW
74
75 $node = $this->find('xpath', $xpath, $exception);
76
77 return $node;
78 }
b11916d3
MG
79
80 /**
81 * Opens the flat navigation drawer if it is not already open
82 *
83 * @When /^I open flat navigation drawer$/
84 * @throws ElementNotFoundException Thrown by behat_base::find
85 */
86 public function i_open_flat_navigation_drawer() {
87 if (!$this->running_javascript()) {
88 // Navigation drawer is always open without JS.
89 return;
90 }
91 $xpath = "//button[contains(@data-action,'toggle-drawer')]";
92 $node = $this->find('xpath', $xpath);
93 $expanded = $node->getAttribute('aria-expanded');
94 if ($expanded === 'false') {
95 $node->click();
3df6e801 96 $this->ensure_node_attribute_is_set($node, 'aria-expanded', 'true');
b11916d3
MG
97 $this->wait_for_pending_js();
98 }
99 }
100
101 /**
102 * Closes the flat navigation drawer if it is open (does nothing if JS disabled)
103 *
104 * @When /^I close flat navigation drawer$/
105 * @throws ElementNotFoundException Thrown by behat_base::find
106 */
107 public function i_close_flat_navigation_drawer() {
108 if (!$this->running_javascript()) {
109 // Navigation drawer can not be closed without JS.
110 return;
111 }
112 $xpath = "//button[contains(@data-action,'toggle-drawer')]";
113 $node = $this->find('xpath', $xpath);
114 $expanded = $node->getAttribute('aria-expanded');
115 if ($expanded === 'true') {
116 $node->click();
117 $this->wait_for_pending_js();
118 }
119 }
120
121 /**
122 * Clicks link with specified id|title|alt|text in the flat navigation drawer.
123 *
124 * @When /^I select "(?P<link_string>(?:[^"]|\\")*)" from flat navigation drawer$/
125 * @throws ElementNotFoundException Thrown by behat_base::find
126 * @param string $link
127 */
128 public function i_select_from_flat_navigation_drawer($link) {
129 $this->i_open_flat_navigation_drawer();
130 $this->execute('behat_general::i_click_on_in_the', [$link, 'link', '#nav-drawer', 'css_element']);
131 }
ebcff7e2
MG
132
133 /**
134 * If we are not on the course main page, click on the course link in the navbar
135 */
136 protected function go_to_main_course_page() {
ebcff7e2 137 $url = $this->getSession()->getCurrentUrl();
ef0d68e9 138 if (!preg_match('|/course/view.php\?id=[\d]+$|', $url)) {
ebcff7e2 139 $this->find('xpath', '//header//div[@id=\'page-navbar\']//a[contains(@href,\'/course/view.php?id=\')]')->click();
ef0d68e9 140 $this->execute('behat_general::wait_until_the_page_is_ready');
ebcff7e2
MG
141 }
142 }
143
144 /**
145 * Finds and clicks a link on the admin page (site administration or course administration)
146 *
147 * @param array $nodelist
148 */
149 protected function select_on_administration_page($nodelist) {
150 $parentnodes = $nodelist;
151 $lastnode = array_pop($parentnodes);
152 $xpath = '//section[@id=\'region-main\']';
153
154 // Check if there is a separate tab for this submenu of the page. If found go to it.
155 if ($parentnodes) {
156 $tabname = behat_context_helper::escape($parentnodes[0]);
8857c715 157 $tabxpath = '//ul[@role=\'tablist\']/li/a[contains(normalize-space(.), ' . $tabname . ')]';
ebcff7e2
MG
158 if ($node = $this->getSession()->getPage()->find('xpath', $tabxpath)) {
159 if ($this->running_javascript()) {
160 // Click on the tab and add 'active' tab to the xpath.
161 $node->click();
162 $xpath .= '//div[contains(@class,\'active\')]';
163 } else {
164 // Add the tab content selector to the xpath.
165 $tabid = behat_context_helper::escape(ltrim($node->getAttribute('href'), '#'));
166 $xpath .= '//div[@id = ' . $tabid . ']';
167 }
168 array_shift($parentnodes);
169 }
170 }
171
172 // Find a section with the parent name in it.
173 if ($parentnodes) {
174 // Find the section on the page (links may be repeating in different sections).
175 $section = behat_context_helper::escape($parentnodes[0]);
176 $xpath .= '//div[@class=\'row\' and contains(.,'.$section.')]';
177 }
178
179 // Find a link and click on it.
180 $linkname = behat_context_helper::escape($lastnode);
8857c715 181 $xpath .= '//a[contains(normalize-space(.), ' . $linkname . ')]';
ebcff7e2
MG
182 if (!$node = $this->getSession()->getPage()->find('xpath', $xpath)) {
183 throw new ElementNotFoundException($this->getSession(), 'Link "' . join(' > ', $nodelist) . '"" not found on the page');
184 }
185 $node->click();
186 $this->wait_for_pending_js();
187 }
188
189 /**
190 * Locates the administration menu in the <header> element and returns its xpath
191 *
192 * @param bool $mustexist if specified throws an exception if menu is not found
193 * @return null|string
194 */
195 protected function find_header_administration_menu($mustexist = false) {
196 $menuxpath = '//header[@id=\'page-header\']//div[contains(@class,\'moodle-actionmenu\')]';
197 if ($mustexist) {
198 $exception = new ElementNotFoundException($this->getSession(), 'Page header administration menu is not found');
199 $this->find('xpath', $menuxpath, $exception);
200 } else if (!$this->getSession()->getPage()->find('xpath', $menuxpath)) {
201 return null;
202 }
203 return $menuxpath;
204 }
205
206 /**
207 * Locates the administration menu on the page (but not in the header) and returns its xpath
208 *
209 * @param bool $mustexist if specified throws an exception if menu is not found
210 * @return null|string
211 */
212 protected function find_page_administration_menu($mustexist = false) {
213 $menuxpath = '//div[@id=\'region-main-settings-menu\']';
214 if ($mustexist) {
215 $exception = new ElementNotFoundException($this->getSession(), 'Page administration menu is not found');
216 $this->find('xpath', $menuxpath, $exception);
217 } else if (!$this->getSession()->getPage()->find('xpath', $menuxpath)) {
218 return null;
219 }
220 return $menuxpath;
221 }
222
223 /**
224 * Toggles administration menu
225 *
226 * @param string $menuxpath (optional) xpath to the page administration menu if already known
227 */
228 protected function toggle_page_administration_menu($menuxpath = null) {
229 if (!$menuxpath) {
230 $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu();
231 }
232 if ($menuxpath && $this->running_javascript()) {
233 $this->find('xpath', $menuxpath . '//a[@data-toggle=\'dropdown\']')->click();
234 $this->wait_for_pending_js();
235 }
236 }
237
238 /**
239 * Finds a page edit cog and select an item from it
240 *
241 * If the page edit cog is in the page header and the item is not found there, click "More..." link
242 * and find the item on the course/frontpage administration page
243 *
244 * @param array $nodelist
245 * @throws ElementNotFoundException
246 */
247 protected function select_from_administration_menu($nodelist) {
248 // Find administration menu.
249 if ($menuxpath = $this->find_header_administration_menu()) {
250 $isheader = true;
251 } else {
252 $menuxpath = $this->find_page_administration_menu(true);
253 $isheader = false;
254 }
255
256 $this->toggle_page_administration_menu($menuxpath);
257
258 if (!$isheader || count($nodelist) == 1) {
259 $lastnode = end($nodelist);
260 $linkname = behat_context_helper::escape($lastnode);
8857c715 261 $link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[contains(normalize-space(.), ' . $linkname . ')]');
ebcff7e2
MG
262 if ($link) {
263 $link->click();
264 $this->wait_for_pending_js();
265 return;
266 }
267 }
268
269 if ($isheader) {
270 // Course administration and Front page administration will have subnodes under "More...".
271 $linkname = behat_context_helper::escape(get_string('morenavigationlinks'));
8857c715 272 $link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[contains(normalize-space(.), ' . $linkname . ')]');
ebcff7e2
MG
273 if ($link) {
274 $link->click();
275 $this->execute('behat_general::wait_until_the_page_is_ready');
276 $this->select_on_administration_page($nodelist);
277 return;
278 }
279 }
280
281 throw new ElementNotFoundException($this->getSession(),
282 'Link "' . join(' > ', $nodelist) . '" not found in the current page edit menu"');
283 }
284
285 public function should_exist_in_current_page_administration($element, $selectortype) {
286 $nodes = array_map('trim', explode('>', $element));
287 $nodetext = end($nodes);
288
289 // Find administration menu.
290 $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu(true);
291
292 $this->toggle_page_administration_menu($menuxpath);
293 $this->execute('behat_general::should_exist_in_the', [$nodetext, $selectortype, $menuxpath, 'xpath_element']);
294 $this->toggle_page_administration_menu($menuxpath);
295 }
296
297 public function should_not_exist_in_current_page_administration($element, $selectortype) {
298 $nodes = array_map('trim', explode('>', $element));
299 $nodetext = end($nodes);
300
301 // Find administration menu.
302 $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu();
303 if (!$menuxpath) {
304 // Menu not found, exit.
305 return;
306 }
307
308 $this->toggle_page_administration_menu($menuxpath);
309 $this->execute('behat_general::should_not_exist_in_the', [$nodetext, $selectortype, $menuxpath, 'xpath_element']);
310 $this->toggle_page_administration_menu($menuxpath);
311 }
312
313 public function i_navigate_to_node_in($nodetext, $parentnodes) {
314 $parentnodes = array_map('trim', explode('>', $parentnodes));
315 $nodelist = array_merge($parentnodes, [$nodetext]);
316 $firstnode = array_shift($nodelist);
317
318 if ($firstnode === get_string('administrationsite')) {
319 $this->i_select_from_flat_navigation_drawer(get_string('administrationsite'));
320 $this->select_on_administration_page($nodelist);
321 return;
322 }
323
324 if ($firstnode === get_string('sitepages')) {
325 if ($nodetext === get_string('calendar', 'calendar')) {
326 $this->i_select_from_flat_navigation_drawer($nodetext);
327 } else {
328 // TODO MDL-57120 other links under "Site pages" are not accessible without navigation block.
329 $this->select_node_in_navigation($nodetext, $parentnodes);
330 }
331 return;
332 }
333
334 if ($firstnode === get_string('courseadministration')) {
335 // Administration menu is available only on the main course page where settings in Administration
336 // block (original purpose of the step) are available on every course page.
337 $this->go_to_main_course_page();
338 }
339
340 $this->select_from_administration_menu($nodelist);
341 }
342
343 public function i_navigate_to_in_current_page_administration($nodetext) {
344 $nodelist = array_map('trim', explode('>', $nodetext));
345 $this->select_from_administration_menu($nodelist);
346 }
347
348 public function i_navigate_to_in_site_administration($nodetext) {
349 $nodelist = array_map('trim', explode('>', $nodetext));
350 $this->i_select_from_flat_navigation_drawer(get_string('administrationsite'));
351 $this->select_on_administration_page($nodelist);
352 }
63e4df60 353}