Commit | Line | Data |
---|---|---|
a1990e50 DM |
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 | * Behat course-related steps definitions. | |
19 | * | |
20 | * @package core_course | |
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__ . '/../../../lib/behat/behat_base.php'); | |
29 | ||
30 | use Behat\Behat\Context\Step\Given as Given, | |
18c84063 DM |
31 | Behat\Gherkin\Node\TableNode as TableNode, |
32 | Behat\Mink\Exception\ExpectationException as ExpectationException, | |
0e575f01 | 33 | Behat\Mink\Exception\DriverException as DriverException, |
18c84063 | 34 | Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException; |
a1990e50 DM |
35 | |
36 | /** | |
37 | * Course-related steps definitions. | |
38 | * | |
39 | * @package core_course | |
40 | * @category test | |
41 | * @copyright 2012 David Monllaó | |
42 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
43 | */ | |
44 | class behat_course extends behat_base { | |
45 | ||
46 | /** | |
47 | * Turns editing mode on. | |
48 | * @Given /^I turn editing mode on$/ | |
49 | */ | |
50 | public function i_turn_editing_mode_on() { | |
dedb9738 | 51 | return new Given('I press "' . get_string('turneditingon') . '"'); |
a1990e50 DM |
52 | } |
53 | ||
54 | /** | |
55 | * Turns editing mode off. | |
56 | * @Given /^I turn editing mode off$/ | |
57 | */ | |
58 | public function i_turn_editing_mode_off() { | |
dedb9738 | 59 | return new Given('I press "' . get_string('turneditingoff') . '"'); |
a1990e50 DM |
60 | } |
61 | ||
df1ff55d DM |
62 | /** |
63 | * Creates a new course with the provided table data matching course settings names with the desired values. | |
64 | * | |
65 | * @Given /^I create a course with:$/ | |
66 | * @param TableNode $table The course data | |
5dc361e1 | 67 | * @return Given[] |
df1ff55d DM |
68 | */ |
69 | public function i_create_a_course_with(TableNode $table) { | |
d1e55a47 DM |
70 | |
71 | $steps = array( | |
df1ff55d | 72 | new Given('I go to the courses management page'), |
8aa3aa3d SH |
73 | new Given('I should see the "'.get_string('categories').'" management page'), |
74 | new Given('I click on category "'.get_string('miscellaneous').'" in the management interface'), | |
75 | new Given('I should see the "'.get_string('categoriesandcoures').'" management page'), | |
d1e55a47 | 76 | new Given('I click on "'.get_string('createnewcourse').'" "link" in the "#course-listing" "css_element"') |
df1ff55d | 77 | ); |
d1e55a47 DM |
78 | |
79 | // If the course format is one of the fields we change how we | |
80 | // fill the form as we need to wait for the form to be set. | |
81 | $rowshash = $table->getRowsHash(); | |
82 | $formatfieldrefs = array(get_string('format'), 'format', 'id_format'); | |
83 | foreach ($formatfieldrefs as $fieldref) { | |
84 | if (!empty($rowshash[$fieldref])) { | |
85 | $formatfield = $fieldref; | |
86 | } | |
87 | } | |
88 | ||
89 | // Setting the format separately. | |
90 | if (!empty($formatfield)) { | |
91 | ||
92 | // Removing the format field from the TableNode. | |
93 | $rows = $table->getRows(); | |
94 | $formatvalue = $rowshash[$formatfield]; | |
95 | foreach ($rows as $key => $row) { | |
96 | if ($row[0] == $formatfield) { | |
97 | unset($rows[$key]); | |
98 | } | |
99 | } | |
100 | $table->setRows($rows); | |
101 | ||
c1faf86b DM |
102 | // Adding a forced wait until editors are loaded as otherwise selenium sometimes tries clicks on the |
103 | // format field when the editor is being rendered and the click misses the field coordinates. | |
fb99ef1d | 104 | $steps[] = new Given('I expand all fieldsets'); |
d1e55a47 | 105 | $steps[] = new Given('I select "' . $formatvalue . '" from "' . $formatfield . '"'); |
c1faf86b | 106 | $steps[] = new Given('I fill the moodle form with:', $table); |
d1e55a47 DM |
107 | } else { |
108 | $steps[] = new Given('I fill the moodle form with:', $table); | |
109 | } | |
110 | ||
111 | $steps[] = new Given('I press "' . get_string('savechanges') . '"'); | |
112 | ||
113 | return $steps; | |
df1ff55d DM |
114 | } |
115 | ||
116 | /** | |
117 | * Goes to the system courses/categories management page. | |
118 | * | |
119 | * @Given /^I go to the courses management page$/ | |
5dc361e1 | 120 | * @return Given[] |
df1ff55d DM |
121 | */ |
122 | public function i_go_to_the_courses_management_page() { | |
6dfd8325 MG |
123 | return array( |
124 | new Given('I am on homepage'), | |
125 | new Given('I expand "' . get_string('administrationsite') . '" node'), | |
126 | new Given('I expand "' . get_string('courses', 'admin') . '" node'), | |
127 | new Given('I follow "' . get_string('coursemgmt', 'admin') . '"') | |
128 | ); | |
df1ff55d DM |
129 | } |
130 | ||
a1990e50 | 131 | /** |
9842e231 | 132 | * Adds the selected activity/resource filling the form data with the specified field/value pairs. Sections 0 and 1 are also allowed on frontpage. |
a1990e50 | 133 | * |
44d5af38 | 134 | * @When /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)" and I fill the form with:$/ |
a1990e50 | 135 | * @param string $activity The activity name |
0e575f01 | 136 | * @param int $section The section number |
a1990e50 | 137 | * @param TableNode $data The activity field/value data |
5dc361e1 | 138 | * @return Given[] |
a1990e50 DM |
139 | */ |
140 | public function i_add_to_section_and_i_fill_the_form_with($activity, $section, TableNode $data) { | |
141 | ||
a1990e50 | 142 | return array( |
38976081 | 143 | new Given('I add a "' . $this->escape($activity) . '" to section "' . $this->escape($section) . '"'), |
a1990e50 | 144 | new Given('I fill the moodle form with:', $data), |
dedb9738 | 145 | new Given('I press "' . get_string('savechangesandreturntocourse') . '"') |
a1990e50 DM |
146 | ); |
147 | } | |
148 | ||
149 | /** | |
9842e231 | 150 | * Opens the activity chooser and opens the activity/resource form page. Sections 0 and 1 are also allowed on frontpage. |
a1990e50 | 151 | * |
44d5af38 | 152 | * @Given /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)"$/ |
1f9ffbdb | 153 | * @throws ElementNotFoundException Thrown by behat_base::find |
a1990e50 | 154 | * @param string $activity |
0e575f01 | 155 | * @param int $section |
a1990e50 DM |
156 | */ |
157 | public function i_add_to_section($activity, $section) { | |
158 | ||
9842e231 MG |
159 | if ($this->getSession()->getPage()->find('css', 'body#page-site-index') && (int)$section <= 1) { |
160 | // We are on the frontpage. | |
161 | if ($section) { | |
162 | // Section 1 represents the contents on the frontpage. | |
163 | $sectionxpath = "//body[@id='page-site-index']/descendant::div[contains(concat(' ',normalize-space(@class),' '),' sitetopic ')]"; | |
164 | } else { | |
165 | // Section 0 represents "Site main menu" block. | |
166 | $sectionxpath = "//div[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]"; | |
167 | } | |
168 | } else { | |
169 | // We are inside the course. | |
170 | $sectionxpath = "//li[@id='section-" . $section . "']"; | |
171 | } | |
38976081 DM |
172 | |
173 | $activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral(ucfirst($activity)); | |
1c00d6f6 DM |
174 | |
175 | if ($this->running_javascript()) { | |
176 | ||
177 | // Clicks add activity or resource section link. | |
178 | $sectionxpath = $sectionxpath . "/descendant::div[@class='section-modchooser']/span/a"; | |
179 | $sectionnode = $this->find('xpath', $sectionxpath); | |
180 | $sectionnode->click(); | |
181 | ||
182 | // Clicks the selected activity if it exists. | |
00ea74cb | 183 | $activityxpath = "//div[@id='chooseform']/descendant::label" . |
38976081 DM |
184 | "/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" . |
185 | "[contains(., $activityliteral)]" . | |
00ea74cb | 186 | "/parent::label/child::input"; |
1c00d6f6 DM |
187 | $activitynode = $this->find('xpath', $activityxpath); |
188 | $activitynode->doubleClick(); | |
189 | ||
190 | } else { | |
191 | // Without Javascript. | |
192 | ||
193 | // Selecting the option from the select box which contains the option. | |
38976081 DM |
194 | $selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" . |
195 | "/descendant::select[contains(., $activityliteral)]"; | |
1c00d6f6 DM |
196 | $selectnode = $this->find('xpath', $selectxpath); |
197 | $selectnode->selectOption($activity); | |
198 | ||
199 | // Go button. | |
200 | $gobuttonxpath = $selectxpath . "/ancestor::form/descendant::input[@type='submit']"; | |
201 | $gobutton = $this->find('xpath', $gobuttonxpath); | |
202 | $gobutton->click(); | |
203 | } | |
204 | ||
a1990e50 DM |
205 | } |
206 | ||
18c84063 DM |
207 | /** |
208 | * Turns course section highlighting on. | |
209 | * | |
210 | * @Given /^I turn section "(?P<section_number>\d+)" highlighting on$/ | |
211 | * @param int $sectionnumber The section number | |
5dc361e1 | 212 | * @return Given[] |
18c84063 DM |
213 | */ |
214 | public function i_turn_section_highlighting_on($sectionnumber) { | |
215 | ||
216 | // Ensures the section exists. | |
217 | $xpath = $this->section_exists($sectionnumber); | |
218 | ||
d1e55a47 | 219 | return new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'); |
18c84063 DM |
220 | } |
221 | ||
222 | /** | |
223 | * Turns course section highlighting off. | |
224 | * | |
225 | * @Given /^I turn section "(?P<section_number>\d+)" highlighting off$/ | |
226 | * @param int $sectionnumber The section number | |
5dc361e1 | 227 | * @return Given[] |
18c84063 DM |
228 | */ |
229 | public function i_turn_section_highlighting_off($sectionnumber) { | |
230 | ||
231 | // Ensures the section exists. | |
232 | $xpath = $this->section_exists($sectionnumber); | |
233 | ||
d1e55a47 | 234 | return new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'); |
18c84063 DM |
235 | } |
236 | ||
237 | /** | |
b918f9f7 DM |
238 | * Shows the specified hidden section. You need to be in the course page and on editing mode. |
239 | * | |
240 | * @Given /^I show section "(?P<section_number>\d+)"$/ | |
241 | * @param int $sectionnumber | |
242 | */ | |
243 | public function i_show_section($sectionnumber) { | |
0e575f01 DM |
244 | $showlink = $this->show_section_icon_exists($sectionnumber); |
245 | $showlink->click(); | |
b918f9f7 | 246 | |
0e575f01 | 247 | if ($this->running_javascript()) { |
d1e55a47 DM |
248 | $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); |
249 | $this->i_wait_until_section_is_available($sectionnumber); | |
0e575f01 | 250 | } |
b918f9f7 DM |
251 | } |
252 | ||
253 | /** | |
254 | * Hides the specified visible section. You need to be in the course page and on editing mode. | |
255 | * | |
256 | * @Given /^I hide section "(?P<section_number>\d+)"$/ | |
257 | * @param int $sectionnumber | |
258 | */ | |
259 | public function i_hide_section($sectionnumber) { | |
0e575f01 DM |
260 | $hidelink = $this->hide_section_icon_exists($sectionnumber); |
261 | $hidelink->click(); | |
b918f9f7 | 262 | |
0e575f01 | 263 | if ($this->running_javascript()) { |
d1e55a47 DM |
264 | $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); |
265 | $this->i_wait_until_section_is_available($sectionnumber); | |
0e575f01 | 266 | } |
b918f9f7 DM |
267 | } |
268 | ||
3f038d6d RT |
269 | /** |
270 | * Go to editing section page for specified section number. You need to be in the course page and on editing mode. | |
271 | * | |
272 | * @Given /^I edit the section "(?P<section_number>\d+)"$/ | |
273 | * @param int $sectionnumber | |
274 | */ | |
275 | public function i_edit_the_section($sectionnumber) { | |
276 | return new Given('I click on "' . get_string('editsummary') . '" "link" in the "#section-' . $sectionnumber . '" "css_element"'); | |
277 | } | |
278 | ||
279 | /** | |
280 | * Edit specified section and fill the form data with the specified field/value pairs. | |
281 | * | |
282 | * @When /^I edit the section "(?P<section_number>\d+)" and I fill the form with:$/ | |
283 | * @param int $sectionnumber The section number | |
284 | * @param TableNode $data The activity field/value data | |
285 | * @return Given[] | |
286 | */ | |
287 | public function i_edit_the_section_and_i_fill_the_form_with($sectionnumber, TableNode $data) { | |
288 | ||
289 | return array( | |
290 | new Given('I edit the section "' . $sectionnumber . '"'), | |
291 | new Given('I fill the moodle form with:', $data), | |
292 | new Given('I press "' . get_string('savechanges') . '"') | |
293 | ); | |
294 | } | |
295 | ||
b918f9f7 DM |
296 | /** |
297 | * Checks if the specified course section hightlighting is turned on. You need to be in the course page on editing mode. | |
18c84063 | 298 | * |
18c84063 | 299 | * @Then /^section "(?P<section_number>\d+)" should be highlighted$/ |
b918f9f7 | 300 | * @throws ExpectationException |
18c84063 DM |
301 | * @param int $sectionnumber The section number |
302 | */ | |
303 | public function section_should_be_highlighted($sectionnumber) { | |
304 | ||
305 | // Ensures the section exists. | |
306 | $xpath = $this->section_exists($sectionnumber); | |
307 | ||
308 | // The important checking, we can not check the img. | |
309 | $xpath = $xpath . "/descendant::img[@alt='" . get_string('markedthistopic') . "'][contains(@src, 'marked')]"; | |
310 | $exception = new ExpectationException('The "' . $sectionnumber . '" section is not highlighted', $this->getSession()); | |
311 | $this->find('xpath', $xpath, $exception); | |
312 | } | |
313 | ||
314 | /** | |
b918f9f7 | 315 | * Checks if the specified course section highlighting is turned off. You need to be in the course page on editing mode. |
18c84063 DM |
316 | * |
317 | * @Then /^section "(?P<section_number>\d+)" should not be highlighted$/ | |
b918f9f7 | 318 | * @throws ExpectationException |
18c84063 DM |
319 | * @param int $sectionnumber The section number |
320 | */ | |
321 | public function section_should_not_be_highlighted($sectionnumber) { | |
322 | ||
323 | // We only catch ExpectationException, ElementNotFoundException should be thrown if the specified section does not exist. | |
324 | try { | |
325 | $this->section_should_be_highlighted($sectionnumber); | |
326 | } catch (ExpectationException $e) { | |
327 | // ExpectedException means that it is not highlighted. | |
328 | return; | |
329 | } | |
330 | ||
331 | throw new ExpectationException('The "' . $sectionnumber . '" section is highlighted', $this->getSession()); | |
332 | } | |
333 | ||
b918f9f7 DM |
334 | /** |
335 | * Checks that the specified section is visible. You need to be in the course page. It can be used being logged as a student and as a teacher on editing mode. | |
336 | * | |
337 | * @Then /^section "(?P<section_number>\d+)" should be hidden$/ | |
338 | * @throws ExpectationException | |
339 | * @throws ElementNotFoundException Thrown by behat_base::find | |
340 | * @param int $sectionnumber | |
341 | */ | |
342 | public function section_should_be_hidden($sectionnumber) { | |
343 | ||
344 | $sectionxpath = $this->section_exists($sectionnumber); | |
345 | ||
d1e55a47 DM |
346 | // Preventive in case there is any action in progress. |
347 | // Adding it here because we are interacting (click) with | |
348 | // the elements, not necessary when we just find(). | |
349 | $this->i_wait_until_section_is_available($sectionnumber); | |
350 | ||
b918f9f7 DM |
351 | // Section should be hidden. |
352 | $exception = new ExpectationException('The section is not hidden', $this->getSession()); | |
38976081 | 353 | $this->find('xpath', $sectionxpath . "[contains(concat(' ', normalize-space(@class), ' '), ' hidden ')]", $exception); |
26df91ca AN |
354 | } |
355 | ||
356 | /** | |
357 | * Checks that all actiities in the specified section are hidden. You need to be in the course page. It can be used being logged as a student and as a teacher on editing mode. | |
358 | * | |
359 | * @Then /^all activities in section "(?P<section_number>\d+)" should be hidden$/ | |
360 | * @throws ExpectationException | |
361 | * @throws ElementNotFoundException Thrown by behat_base::find | |
362 | * @param int $sectionnumber | |
363 | */ | |
364 | public function section_activities_should_be_hidden($sectionnumber) { | |
365 | $sectionxpath = $this->section_exists($sectionnumber); | |
366 | ||
367 | // Preventive in case there is any action in progress. | |
368 | // Adding it here because we are interacting (click) with | |
369 | // the elements, not necessary when we just find(). | |
370 | $this->i_wait_until_section_is_available($sectionnumber); | |
b918f9f7 DM |
371 | |
372 | // The checking are different depending on user permissions. | |
373 | if ($this->is_course_editor()) { | |
374 | ||
375 | // The section must be hidden. | |
376 | $this->show_section_icon_exists($sectionnumber); | |
377 | ||
378 | // If there are activities they should be hidden and the visibility icon should not be available. | |
379 | if ($activities = $this->get_section_activities($sectionxpath)) { | |
380 | ||
381 | $dimmedexception = new ExpectationException('There are activities that are not dimmed', $this->getSession()); | |
b918f9f7 | 382 | foreach ($activities as $activity) { |
b918f9f7 | 383 | // Dimmed. |
38976081 DM |
384 | $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' activityinstance ')]" . |
385 | "/a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity); | |
b918f9f7 DM |
386 | } |
387 | } | |
b918f9f7 DM |
388 | } else { |
389 | // There shouldn't be activities. | |
390 | if ($this->get_section_activities($sectionxpath)) { | |
391 | throw new ExpectationException('There are activities in the section and they should be hidden', $this->getSession()); | |
392 | } | |
393 | } | |
26df91ca | 394 | |
b918f9f7 DM |
395 | } |
396 | ||
397 | /** | |
398 | * Checks that the specified section is visible. You need to be in the course page. It can be used being logged as a student and as a teacher on editing mode. | |
399 | * | |
400 | * @Then /^section "(?P<section_number>\d+)" should be visible$/ | |
401 | * @throws ExpectationException | |
402 | * @param int $sectionnumber | |
403 | */ | |
404 | public function section_should_be_visible($sectionnumber) { | |
405 | ||
406 | $sectionxpath = $this->section_exists($sectionnumber); | |
407 | ||
408 | // Section should not be hidden. | |
38976081 DM |
409 | $xpath = $sectionxpath . "[not(contains(concat(' ', normalize-space(@class), ' '), ' hidden '))]"; |
410 | if (!$this->getSession()->getPage()->find('xpath', $xpath)) { | |
b918f9f7 DM |
411 | throw new ExpectationException('The section is hidden', $this->getSession()); |
412 | } | |
413 | ||
414 | // Hide section button should be visible. | |
415 | if ($this->is_course_editor()) { | |
416 | $this->hide_section_icon_exists($sectionnumber); | |
417 | } | |
418 | } | |
419 | ||
0e575f01 DM |
420 | /** |
421 | * Moves up the specified section, this step only works with Javascript disabled. Editing mode should be on. | |
422 | * | |
423 | * @Given /^I move up section "(?P<section_number>\d+)"$/ | |
424 | * @throws DriverException Step not available when Javascript is enabled | |
425 | * @param int $sectionnumber | |
426 | */ | |
427 | public function i_move_up_section($sectionnumber) { | |
428 | ||
429 | if ($this->running_javascript()) { | |
430 | throw new DriverException('Move a section up step is not available with Javascript enabled'); | |
431 | } | |
432 | ||
433 | // Ensures the section exists. | |
434 | $sectionxpath = $this->section_exists($sectionnumber); | |
435 | ||
436 | // Follows the link | |
437 | $moveuplink = $this->get_node_in_container('link', get_string('moveup'), 'xpath_element', $sectionxpath); | |
438 | $moveuplink->click(); | |
439 | } | |
440 | ||
441 | /** | |
442 | * Moves down the specified section, this step only works with Javascript disabled. Editing mode should be on. | |
443 | * | |
444 | * @Given /^I move down section "(?P<section_number>\d+)"$/ | |
445 | * @throws DriverException Step not available when Javascript is enabled | |
446 | * @param int $sectionnumber | |
447 | */ | |
448 | public function i_move_down_section($sectionnumber) { | |
449 | ||
450 | if ($this->running_javascript()) { | |
451 | throw new DriverException('Move a section down step is not available with Javascript enabled'); | |
452 | } | |
453 | ||
454 | // Ensures the section exists. | |
455 | $sectionxpath = $this->section_exists($sectionnumber); | |
456 | ||
457 | // Follows the link | |
458 | $movedownlink = $this->get_node_in_container('link', get_string('movedown'), 'xpath_element', $sectionxpath); | |
459 | $movedownlink->click(); | |
460 | } | |
461 | ||
bf648567 DM |
462 | /** |
463 | * Checks that the specified activity is visible. You need to be in the course page. It can be used being logged as a student and as a teacher on editing mode. | |
464 | * | |
465 | * @Then /^"(?P<activity_or_resource_string>(?:[^"]|\\")*)" activity should be visible$/ | |
466 | * @param string $activityname | |
5dc361e1 | 467 | * @throws ExpectationException |
bf648567 DM |
468 | */ |
469 | public function activity_should_be_visible($activityname) { | |
470 | ||
471 | // The activity must exists and be visible. | |
472 | $activitynode = $this->get_activity_node($activityname); | |
473 | ||
474 | if ($this->is_course_editor()) { | |
475 | ||
476 | // The activity should not be dimmed. | |
477 | try { | |
478 | $this->find('css', 'a.dimmed', false, $activitynode); | |
479 | throw new ExpectationException('"' . $activityname . '" is hidden', $this->getSession()); | |
480 | } catch (ElementNotFoundException $e) { | |
481 | // All ok. | |
482 | } | |
483 | ||
484 | // The 'Hide' button should be available. | |
485 | $nohideexception = new ExpectationException('"' . $activityname . '" don\'t have a "' . get_string('hide') . '" icon', $this->getSession()); | |
486 | $this->find('named', array('link', get_string('hide')), $nohideexception, $activitynode); | |
487 | } | |
488 | } | |
489 | ||
490 | /** | |
491 | * Checks that the specified activity is hidden. You need to be in the course page. It can be used being logged as a student and as a teacher on editing mode. | |
492 | * | |
493 | * @Then /^"(?P<activity_or_resource_string>(?:[^"]|\\")*)" activity should be hidden$/ | |
494 | * @param string $activityname | |
5dc361e1 | 495 | * @throws ExpectationException |
bf648567 DM |
496 | */ |
497 | public function activity_should_be_hidden($activityname) { | |
498 | ||
499 | if ($this->is_course_editor()) { | |
500 | ||
501 | // The activity should exists. | |
502 | $activitynode = $this->get_activity_node($activityname); | |
503 | ||
504 | // Should be hidden. | |
505 | $exception = new ExpectationException('"' . $activityname . '" is not dimmed', $this->getSession()); | |
506 | $this->find('css', 'a.dimmed', $exception, $activitynode); | |
507 | ||
508 | // Also 'Show' icon. | |
509 | $noshowexception = new ExpectationException('"' . $activityname . '" don\'t have a "' . get_string('show') . '" icon', $this->getSession()); | |
510 | $this->find('named', array('link', get_string('show')), $noshowexception, $activitynode); | |
511 | ||
512 | } else { | |
513 | ||
514 | // It should not exists at all. | |
515 | try { | |
516 | $this->find_link($activityname); | |
517 | throw new ExpectationException('The "' . $activityname . '" should not appear'); | |
518 | } catch (ElementNotFoundException $e) { | |
519 | // This is good, the activity should not be there. | |
520 | } | |
521 | } | |
522 | ||
523 | } | |
524 | ||
0e575f01 | 525 | /** |
7daab401 | 526 | * Moves the specified activity to the first slot of a section. This step is experimental when using it in Javascript tests. Editing mode should be on. |
0e575f01 DM |
527 | * |
528 | * @Given /^I move "(?P<activity_name_string>(?:[^"]|\\")*)" activity to section "(?P<section_number>\d+)"$/ | |
529 | * @param string $activityname The activity name | |
530 | * @param int $sectionnumber The number of section | |
5dc361e1 | 531 | * @return Given[] |
0e575f01 DM |
532 | */ |
533 | public function i_move_activity_to_section($activityname, $sectionnumber) { | |
534 | ||
535 | // Ensure the destination is valid. | |
536 | $sectionxpath = $this->section_exists($sectionnumber); | |
537 | ||
538 | $activitynode = $this->get_activity_element('.editing_move img', 'css_element', $activityname); | |
539 | ||
540 | // JS enabled. | |
541 | if ($this->running_javascript()) { | |
542 | ||
38976081 | 543 | $destinationxpath = $sectionxpath . "/descendant::ul[contains(concat(' ', normalize-space(@class), ' '), ' yui3-dd-drop ')]"; |
0e575f01 DM |
544 | |
545 | return array( | |
38976081 DM |
546 | new Given('I drag "' . $this->escape($activitynode->getXpath()) . '" "xpath_element" ' . |
547 | 'and I drop it in "' . $this->escape($destinationxpath) . '" "xpath_element"'), | |
0e575f01 DM |
548 | ); |
549 | ||
550 | } else { | |
551 | // Following links with no-JS. | |
552 | ||
553 | // Moving to the fist spot of the section (before all other section's activities). | |
554 | return array( | |
38976081 DM |
555 | new Given('I click on "a.editing_move" "css_element" in the "' . $this->escape($activityname) . '" activity'), |
556 | new Given('I click on "li.movehere a" "css_element" in the "' . $this->escape($sectionxpath) . '" "xpath_element"'), | |
0e575f01 DM |
557 | ); |
558 | } | |
559 | } | |
560 | ||
561 | /** | |
562 | * Edits the activity name through the edit activity; this step only works with Javascript enabled. Editing mode should be on. | |
563 | * | |
564 | * @Given /^I change "(?P<activity_name_string>(?:[^"]|\\")*)" activity name to "(?P<new_name_string>(?:[^"]|\\")*)"$/ | |
565 | * @throws DriverException Step not available when Javascript is disabled | |
566 | * @param string $activityname | |
567 | * @param string $newactivityname | |
5dc361e1 | 568 | * @return Given[] |
0e575f01 DM |
569 | */ |
570 | public function i_change_activity_name_to($activityname, $newactivityname) { | |
571 | ||
572 | if (!$this->running_javascript()) { | |
573 | throw new DriverException('Change activity name step is not available with Javascript disabled'); | |
574 | } | |
575 | ||
576 | // Adding chr(10) to save changes. | |
e5de4933 | 577 | $activity = $this->escape($activityname); |
0e575f01 | 578 | return array( |
e5de4933 | 579 | new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $activity .'" activity'), |
d1e55a47 | 580 | new Given('I fill in "title" with "' . $this->escape($newactivityname) . chr(10) . '"') |
0e575f01 DM |
581 | ); |
582 | } | |
583 | ||
2a9275c4 DM |
584 | /** |
585 | * Opens an activity actions menu if it is not already opened. | |
586 | * | |
587 | * @Given /^I open "(?P<activity_name_string>(?:[^"]|\\")*)" actions menu$/ | |
588 | * @throws DriverException The step is not available when Javascript is disabled | |
589 | * @param string $activityname | |
590 | * @return Given | |
591 | */ | |
592 | public function i_open_actions_menu($activityname) { | |
593 | ||
594 | if (!$this->running_javascript()) { | |
595 | throw new DriverException('Activities actions menu not available when Javascript is disabled'); | |
596 | } | |
597 | ||
598 | // If it is already opened we do nothing. | |
599 | $activitynode = $this->get_activity_node($activityname); | |
600 | $classes = array_flip(explode(' ', $activitynode->getAttribute('class'))); | |
601 | if (!empty($classes['action-menu-shown'])) { | |
602 | return; | |
603 | } | |
604 | ||
047a8800 | 605 | return new Given('I click on "a[role=\'menuitem\']" "css_element" in the "' . $this->escape($activityname) . '" activity'); |
2a9275c4 DM |
606 | } |
607 | ||
d1e55a47 DM |
608 | /** |
609 | * Closes an activity actions menu if it is not already closed. | |
610 | * | |
611 | * @Given /^I close "(?P<activity_name_string>(?:[^"]|\\")*)" actions menu$/ | |
612 | * @throws DriverException The step is not available when Javascript is disabled | |
613 | * @param string $activityname | |
614 | * @return Given | |
615 | */ | |
616 | public function i_close_actions_menu($activityname) { | |
617 | ||
618 | if (!$this->running_javascript()) { | |
619 | throw new DriverException('Activities actions menu not available when Javascript is disabled'); | |
620 | } | |
621 | ||
622 | // If it is already closed we do nothing. | |
623 | $activitynode = $this->get_activity_node($activityname); | |
624 | $classes = array_flip(explode(' ', $activitynode->getAttribute('class'))); | |
625 | if (empty($classes['action-menu-shown'])) { | |
626 | return; | |
627 | } | |
628 | ||
629 | return new Given('I click on "a[role=\'menuitem\']" "css_element" in the "' . $this->escape($activityname) . '" activity'); | |
630 | } | |
631 | ||
af4d19ab AN |
632 | /** |
633 | * Checks that the specified activity's action menu is open. | |
634 | * | |
635 | * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" actions menu should be open$/ | |
636 | * @throws DriverException The step is not available when Javascript is disabled | |
637 | * @param string $activityname | |
638 | */ | |
639 | public function actions_menu_should_be_open($activityname) { | |
640 | ||
641 | if (!$this->running_javascript()) { | |
642 | throw new DriverException('Activities actions menu not available when Javascript is disabled'); | |
643 | } | |
644 | ||
645 | // If it is already closed we do nothing. | |
646 | $activitynode = $this->get_activity_node($activityname); | |
647 | $classes = array_flip(explode(' ', $activitynode->getAttribute('class'))); | |
648 | if (empty($classes['action-menu-shown'])) { | |
649 | throw new ExpectationException(sprintf("The action menu for '%s' is not open", $activityname), $this->getSession()); | |
650 | } | |
651 | ||
652 | return; | |
653 | } | |
654 | ||
0e575f01 DM |
655 | /** |
656 | * Indents to the right the activity or resource specified by it's name. Editing mode should be on. | |
657 | * | |
658 | * @Given /^I indent right "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/ | |
659 | * @param string $activityname | |
5dc361e1 | 660 | * @return Given[] |
0e575f01 DM |
661 | */ |
662 | public function i_indent_right_activity($activityname) { | |
663 | ||
e5de4933 SH |
664 | $steps = array(); |
665 | $activity = $this->escape($activityname); | |
666 | if ($this->running_javascript()) { | |
2a9275c4 | 667 | $steps[] = new Given('I open "' . $activity . '" actions menu'); |
e5de4933 SH |
668 | } |
669 | $steps[] = new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $activity . '" activity'); | |
0e575f01 | 670 | |
0e575f01 DM |
671 | return $steps; |
672 | } | |
673 | ||
674 | /** | |
675 | * Indents to the left the activity or resource specified by it's name. Editing mode should be on. | |
676 | * | |
677 | * @Given /^I indent left "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/ | |
678 | * @param string $activityname | |
5dc361e1 | 679 | * @return Given[] |
0e575f01 DM |
680 | */ |
681 | public function i_indent_left_activity($activityname) { | |
682 | ||
e5de4933 SH |
683 | $steps = array(); |
684 | $activity = $this->escape($activityname); | |
685 | if ($this->running_javascript()) { | |
2a9275c4 | 686 | $steps[] = new Given('I open "' . $activity . '" actions menu'); |
e5de4933 SH |
687 | } |
688 | $steps[] = new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $activity . '" activity'); | |
0e575f01 | 689 | |
0e575f01 DM |
690 | return $steps; |
691 | ||
692 | } | |
693 | ||
694 | /** | |
7daab401 | 695 | * Deletes the activity or resource specified by it's name. This step is experimental when using it in Javascript tests. You should be in the course page with editing mode on. |
0e575f01 DM |
696 | * |
697 | * @Given /^I delete "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/ | |
698 | * @param string $activityname | |
5dc361e1 | 699 | * @return Given[] |
0e575f01 DM |
700 | */ |
701 | public function i_delete_activity($activityname) { | |
702 | ||
703 | $deletestring = get_string('delete'); | |
704 | ||
fbd904ef DM |
705 | $steps = array( |
706 | new Given('I click on "' . $this->escape($deletestring) . '" "link" in the "' . $this->escape($activityname) . '" activity') | |
707 | ); | |
708 | ||
0e575f01 DM |
709 | // JS enabled. |
710 | // Not using chain steps here because the exceptions catcher have problems detecting | |
711 | // JS modal windows and avoiding interacting them at the same time. | |
712 | if ($this->running_javascript()) { | |
fbd904ef | 713 | $steps[] = new Given('I click on "' . get_string('yes') . '" "button" in the "Confirm" "dialogue"'); |
0e575f01 | 714 | } else { |
fbd904ef | 715 | $steps[] = new Given('I press "' . get_string('yes') . '"'); |
0e575f01 | 716 | } |
fbd904ef DM |
717 | |
718 | return $steps; | |
0e575f01 DM |
719 | } |
720 | ||
721 | /** | |
722 | * Duplicates the activity or resource specified by it's name. You should be in the course page with editing mode on. | |
723 | * | |
724 | * @Given /^I duplicate "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/ | |
725 | * @param string $activityname | |
5dc361e1 | 726 | * @return Given[] |
0e575f01 DM |
727 | */ |
728 | public function i_duplicate_activity($activityname) { | |
e5de4933 SH |
729 | $steps = array(); |
730 | $activity = $this->escape($activityname); | |
731 | if ($this->running_javascript()) { | |
2a9275c4 | 732 | $steps[] = new Given('I open "' . $activity . '" actions menu'); |
e5de4933 SH |
733 | } |
734 | $steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity'); | |
d1e55a47 | 735 | if (!$this->running_javascript()) { |
047a8800 DM |
736 | $steps[] = new Given('I press "' . get_string('continue') .'"'); |
737 | $steps[] = new Given('I press "' . get_string('duplicatecontcourse') .'"'); | |
738 | } | |
e5de4933 | 739 | return $steps; |
0e575f01 DM |
740 | } |
741 | ||
742 | /** | |
743 | * Duplicates the activity or resource and modifies the new activity with the provided data. You should be in the course page with editing mode on. | |
744 | * | |
745 | * @Given /^I duplicate "(?P<activity_name_string>(?:[^"]|\\")*)" activity editing the new copy with:$/ | |
746 | * @param string $activityname | |
747 | * @param TableNode $data | |
5dc361e1 | 748 | * @return Given[] |
0e575f01 DM |
749 | */ |
750 | public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) { | |
047a8800 | 751 | |
e5de4933 | 752 | $steps = array(); |
047a8800 | 753 | |
e5de4933 | 754 | $activity = $this->escape($activityname); |
d1e55a47 | 755 | $activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname); |
047a8800 | 756 | |
e5de4933 | 757 | if ($this->running_javascript()) { |
047a8800 DM |
758 | $steps[] = new Given('I duplicate "' . $activity . '" activity'); |
759 | ||
d1e55a47 DM |
760 | // We wait until the AJAX request finishes and the section is visible again. |
761 | $hiddenlightboxxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityliteral)]" . | |
762 | "/ancestor::li[contains(concat(' ', normalize-space(@class), ' '), ' section ')]" . | |
763 | "/descendant::div[contains(concat(' ', @class, ' '), ' lightbox ')][contains(@style, 'display: none')]"; | |
764 | $steps[] = new Given('I wait until the page is ready'); | |
765 | $steps[] = new Given('I wait until "' . $this->escape($hiddenlightboxxpath) .'" "xpath_element" exists'); | |
766 | ||
767 | // Close the original activity actions menu. | |
768 | $steps[] = new Given('I close "' . $activity . '" actions menu'); | |
769 | ||
047a8800 | 770 | // Determine the future new activity xpath from the former one. |
047a8800 DM |
771 | $duplicatedxpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityliteral)]" . |
772 | "/following-sibling::li"; | |
773 | $duplicatedactionsmenuxpath = $duplicatedxpath . "/descendant::a[@role='menuitem']"; | |
774 | ||
775 | // The next sibling of the former activity will be the duplicated one, so we click on it from it's xpath as, at | |
776 | // this point, it don't even exists in the DOM (the steps are executed when we return them). | |
777 | $steps[] = new Given('I click on "' . $this->escape($duplicatedactionsmenuxpath) . '" "xpath_element"'); | |
778 | ||
779 | // We force the xpath as otherwise mink tries to interact with the former one. | |
780 | $steps[] = new Given('I click on "' . get_string('editsettings') . '" "link" in the "' . $this->escape($duplicatedxpath) . '" "xpath_element"'); | |
781 | } else { | |
782 | $steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity'); | |
783 | $steps[] = new Given('I press "' . get_string('continue') .'"'); | |
784 | $steps[] = new Given('I press "' . get_string('duplicatecontedit') . '"'); | |
e5de4933 | 785 | } |
e5de4933 SH |
786 | $steps[] = new Given('I fill the moodle form with:', $data); |
787 | $steps[] = new Given('I press "' . get_string('savechangesandreturntocourse') . '"'); | |
788 | return $steps; | |
0e575f01 DM |
789 | } |
790 | ||
d1e55a47 DM |
791 | /** |
792 | * Waits until the section is available to interact with it. Useful when the section is performing an action and the section is overlayed with a loading layout. | |
793 | * | |
794 | * Using the protected method as this method will be usually | |
795 | * called by other methods which are not returning a set of | |
796 | * steps and performs the actions directly, so it would not | |
797 | * be executed if it returns another step. | |
798 | * | |
799 | * Hopefully we would not require test writers to use this step | |
800 | * and we will manage it from other step definitions. | |
801 | * | |
802 | * @Given /^I wait until section "(?P<section_number>\d+)" is available$/ | |
803 | * @param int $sectionnumber | |
804 | * @return void | |
805 | */ | |
806 | public function i_wait_until_section_is_available($sectionnumber) { | |
807 | ||
808 | // Looks for a hidden lightbox or a non-existent lightbox in that section. | |
809 | $sectionxpath = $this->section_exists($sectionnumber); | |
810 | $hiddenlightboxxpath = $sectionxpath . "/descendant::div[contains(concat(' ', @class, ' '), ' lightbox ')][contains(@style, 'display: none')]" . | |
811 | " | " . | |
812 | $sectionxpath . "[count(child::div[contains(@class, 'lightbox')]) = 0]"; | |
813 | ||
814 | $this->ensure_element_exists($hiddenlightboxxpath, 'xpath_element'); | |
815 | } | |
816 | ||
0e575f01 DM |
817 | /** |
818 | * Clicks on the specified element of the activity. You should be in the course page with editing mode turned on. | |
819 | * | |
820 | * @Given /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<activity_name_string>[^"]*)" activity$/ | |
821 | * @param string $element | |
822 | * @param string $selectortype | |
823 | * @param string $activityname | |
824 | */ | |
825 | public function i_click_on_in_the_activity($element, $selectortype, $activityname) { | |
826 | $element = $this->get_activity_element($element, $selectortype, $activityname); | |
827 | $element->click(); | |
828 | } | |
829 | ||
830 | /** | |
831 | * Clicks on the specified element inside the activity container. | |
832 | * | |
833 | * @throws ElementNotFoundException | |
834 | * @param string $element | |
835 | * @param string $selectortype | |
836 | * @param string $activityname | |
837 | * @return NodeElement | |
838 | */ | |
839 | protected function get_activity_element($element, $selectortype, $activityname) { | |
840 | $activitynode = $this->get_activity_node($activityname); | |
841 | ||
842 | // Transforming to Behat selector/locator. | |
843 | list($selector, $locator) = $this->transform_selector($selectortype, $element); | |
844 | $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . $selectortype . '" in "' . $activityname . '" '); | |
845 | ||
846 | return $this->find($selector, $locator, $exception, $activitynode); | |
847 | } | |
848 | ||
18c84063 DM |
849 | /** |
850 | * Checks if the course section exists. | |
851 | * | |
852 | * @throws ElementNotFoundException Thrown by behat_base::find | |
853 | * @param int $sectionnumber | |
b918f9f7 | 854 | * @return string The xpath of the section. |
18c84063 DM |
855 | */ |
856 | protected function section_exists($sectionnumber) { | |
857 | ||
858 | // Just to give more info in case it does not exist. | |
859 | $xpath = "//li[@id='section-" . $sectionnumber . "']"; | |
860 | $exception = new ElementNotFoundException($this->getSession(), "Section $sectionnumber "); | |
861 | $this->find('xpath', $xpath, $exception); | |
862 | ||
863 | return $xpath; | |
864 | } | |
b918f9f7 DM |
865 | |
866 | /** | |
867 | * Returns the show section icon or throws an exception. | |
868 | * | |
869 | * @throws ElementNotFoundException Thrown by behat_base::find | |
870 | * @param int $sectionnumber | |
871 | * @return NodeElement | |
872 | */ | |
873 | protected function show_section_icon_exists($sectionnumber) { | |
874 | ||
875 | // Gets the section xpath and ensure it exists. | |
876 | $xpath = $this->section_exists($sectionnumber); | |
877 | ||
878 | // We need to know the course format as the text strings depends on them. | |
879 | $courseformat = $this->get_course_format(); | |
880 | ||
881 | // Checking the show button alt text and show icon. | |
38976081 DM |
882 | $showtext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('showfromothers', $courseformat)); |
883 | $linkxpath = $xpath . "/descendant::a[@title=$showtext]"; | |
884 | $imgxpath = $linkxpath . "/descendant::img[@alt=$showtext][contains(@src, 'show')]"; | |
b918f9f7 DM |
885 | |
886 | $exception = new ElementNotFoundException($this->getSession(), 'Show section icon '); | |
0e575f01 DM |
887 | $this->find('xpath', $imgxpath, $exception); |
888 | ||
889 | // Returing the link so both Non-JS and JS browsers can interact with it. | |
890 | return $this->find('xpath', $linkxpath, $exception); | |
b918f9f7 DM |
891 | } |
892 | ||
893 | /** | |
894 | * Returns the hide section icon link if it exists or throws exception. | |
895 | * | |
896 | * @throws ElementNotFoundException Thrown by behat_base::find | |
897 | * @param int $sectionnumber | |
898 | * @return NodeElement | |
899 | */ | |
900 | protected function hide_section_icon_exists($sectionnumber) { | |
901 | ||
902 | // Gets the section xpath and ensure it exists. | |
903 | $xpath = $this->section_exists($sectionnumber); | |
904 | ||
905 | // We need to know the course format as the text strings depends on them. | |
906 | $courseformat = $this->get_course_format(); | |
907 | ||
908 | // Checking the hide button alt text and hide icon. | |
38976081 DM |
909 | $hidetext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('hidefromothers', $courseformat)); |
910 | $linkxpath = $xpath . "/descendant::a[@title=$hidetext]"; | |
911 | $imgxpath = $linkxpath . "/descendant::img[@alt=$hidetext][contains(@src, 'hide')]"; | |
b918f9f7 DM |
912 | |
913 | $exception = new ElementNotFoundException($this->getSession(), 'Hide section icon '); | |
0e575f01 DM |
914 | $this->find('xpath', $imgxpath, $exception); |
915 | ||
916 | // Returing the link so both Non-JS and JS browsers can interact with it. | |
917 | return $this->find('xpath', $linkxpath, $exception); | |
b918f9f7 DM |
918 | } |
919 | ||
920 | /** | |
921 | * Gets the current course format. | |
922 | * | |
923 | * @throws ExpectationException If we are not in the course view page. | |
924 | * @return string The course format in a frankenstyled name. | |
925 | */ | |
926 | protected function get_course_format() { | |
927 | ||
928 | $exception = new ExpectationException('You are not in a course page', $this->getSession()); | |
929 | ||
930 | // The moodle body's id attribute contains the course format. | |
931 | $node = $this->getSession()->getPage()->find('css', 'body'); | |
932 | if (!$node) { | |
933 | throw $exception; | |
934 | } | |
935 | ||
936 | if (!$bodyid = $node->getAttribute('id')) { | |
937 | throw $exception; | |
938 | } | |
939 | ||
940 | if (strstr($bodyid, 'page-course-view-') === false) { | |
941 | throw $exception; | |
942 | } | |
943 | ||
944 | return 'format_' . str_replace('page-course-view-', '', $bodyid); | |
945 | } | |
946 | ||
947 | /** | |
948 | * Gets the section's activites DOM nodes. | |
949 | * | |
950 | * @param string $sectionxpath | |
951 | * @return array NodeElement instances | |
952 | */ | |
953 | protected function get_section_activities($sectionxpath) { | |
954 | ||
38976081 | 955 | $xpath = $sectionxpath . "/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]"; |
b918f9f7 DM |
956 | |
957 | // We spin here, as activities usually require a lot of time to load. | |
958 | try { | |
959 | $activities = $this->find_all('xpath', $xpath); | |
960 | } catch (ElementNotFoundException $e) { | |
961 | return false; | |
962 | } | |
963 | ||
964 | return $activities; | |
965 | } | |
966 | ||
bf648567 DM |
967 | /** |
968 | * Returns the DOM node of the activity from <li>. | |
969 | * | |
970 | * @throws ElementNotFoundException Thrown by behat_base::find | |
971 | * @param string $activityname The activity name | |
972 | * @return NodeElement | |
973 | */ | |
974 | protected function get_activity_node($activityname) { | |
975 | ||
38976081 DM |
976 | $activityname = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname); |
977 | $xpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityname)]"; | |
bf648567 DM |
978 | |
979 | return $this->find('xpath', $xpath); | |
980 | } | |
981 | ||
d1e55a47 DM |
982 | /** |
983 | * Gets the activity instance name from the activity node. | |
984 | * | |
985 | * @throws ElementNotFoundException | |
986 | * @param NodeElement $activitynode | |
987 | * @return string | |
988 | */ | |
989 | protected function get_activity_name($activitynode) { | |
990 | $instancenamenode = $this->find('xpath', "//span[contains(concat(' ', normalize-space(@class), ' '), ' instancename ')]", false, $activitynode); | |
991 | return $instancenamenode->getText(); | |
992 | } | |
993 | ||
b918f9f7 DM |
994 | /** |
995 | * Returns whether the user can edit the course contents or not. | |
996 | * | |
997 | * @return bool | |
998 | */ | |
999 | protected function is_course_editor() { | |
1000 | ||
1001 | // We don't need to behat_base::spin() here as all is already loaded. | |
dedb9738 DM |
1002 | if (!$this->getSession()->getPage()->findButton(get_string('turneditingoff')) && |
1003 | !$this->getSession()->getPage()->findButton(get_string('turneditingon'))) { | |
b918f9f7 DM |
1004 | return false; |
1005 | } | |
1006 | ||
1007 | return true; | |
1008 | } | |
1009 | ||
5dc361e1 SH |
1010 | /** |
1011 | * Returns the id of the category with the given idnumber. | |
8aa3aa3d SH |
1012 | * |
1013 | * Please note that this function requires the category to exist. If it does not exist an ExpectationException is thrown. | |
1014 | * | |
5dc361e1 SH |
1015 | * @param string $idnumber |
1016 | * @return string | |
8aa3aa3d | 1017 | * @throws ExpectationException |
5dc361e1 SH |
1018 | */ |
1019 | protected function get_category_id($idnumber) { | |
1020 | global $DB; | |
8aa3aa3d SH |
1021 | try { |
1022 | return $DB->get_field('course_categories', 'id', array('idnumber' => $idnumber), MUST_EXIST); | |
1023 | } catch (dml_missing_record_exception $ex) { | |
1024 | throw new ExpectationException(sprintf("There is no category in the database with the idnumber '%s'", $idnumber)); | |
1025 | } | |
5dc361e1 SH |
1026 | } |
1027 | ||
1028 | /** | |
1029 | * Returns the id of the course with the given idnumber. | |
8aa3aa3d SH |
1030 | * |
1031 | * Please note that this function requires the category to exist. If it does not exist an ExpectationException is thrown. | |
1032 | * | |
5dc361e1 SH |
1033 | * @param string $idnumber |
1034 | * @return string | |
8aa3aa3d | 1035 | * @throws ExpectationException |
5dc361e1 SH |
1036 | */ |
1037 | protected function get_course_id($idnumber) { | |
1038 | global $DB; | |
8aa3aa3d SH |
1039 | try { |
1040 | return $DB->get_field('course', 'id', array('idnumber' => $idnumber), MUST_EXIST); | |
1041 | } catch (dml_missing_record_exception $ex) { | |
1042 | throw new ExpectationException(sprintf("There is no course in the database with the idnumber '%s'", $idnumber)); | |
1043 | } | |
5dc361e1 SH |
1044 | } |
1045 | ||
1046 | /** | |
1047 | * Returns the category node from within the listing on the management page. | |
1048 | * | |
1049 | * @param string $idnumber | |
1050 | * @return \Behat\Mink\Element\NodeElement | |
1051 | */ | |
1052 | protected function get_management_category_listing_node_by_idnumber($idnumber) { | |
1053 | $id = $this->get_category_id($idnumber); | |
1054 | $selector = sprintf('#category-listing .listitem-category[data-id="%d"] > div', $id); | |
1055 | return $this->find('css', $selector); | |
1056 | } | |
1057 | ||
1058 | /** | |
8aa3aa3d SH |
1059 | * Returns a category node from within the management interface. |
1060 | * | |
1061 | * @param string $name The name of the category. | |
b155a170 | 1062 | * @param bool $link If set to true we'll resolve to the link rather than just the node. |
5dc361e1 SH |
1063 | * @return \Behat\Mink\Element\NodeElement |
1064 | */ | |
b155a170 SH |
1065 | protected function get_management_category_listing_node_by_name($name, $link = false) { |
1066 | $selector = "//div[@id='category-listing']//li[contains(concat(' ', normalize-space(@class), ' '), ' listitem-category ')]//a[text()='{$name}']"; | |
1067 | if ($link === false) { | |
3ea677e3 | 1068 | $selector .= "/ancestor::li[@data-id][1]"; |
b155a170 | 1069 | } |
5dc361e1 SH |
1070 | return $this->find('xpath', $selector); |
1071 | } | |
1072 | ||
1073 | /** | |
8aa3aa3d SH |
1074 | * Returns a course node from within the management interface. |
1075 | * | |
1076 | * @param string $name The name of the course. | |
b155a170 | 1077 | * @param bool $link If set to true we'll resolve to the link rather than just the node. |
5dc361e1 SH |
1078 | * @return \Behat\Mink\Element\NodeElement |
1079 | */ | |
b155a170 SH |
1080 | protected function get_management_course_listing_node_by_name($name, $link = false) { |
1081 | $selector = "//div[@id='course-listing']//li[contains(concat(' ', @class, ' '), ' listitem-course ')]//a[text()='{$name}']"; | |
1082 | if ($link === false) { | |
1083 | $selector .= "/ancestor::li[@data-id]"; | |
1084 | } | |
5dc361e1 SH |
1085 | return $this->find('xpath', $selector); |
1086 | } | |
1087 | ||
1088 | /** | |
1089 | * Returns the course node from within the listing on the management page. | |
1090 | * | |
1091 | * @param string $idnumber | |
1092 | * @return \Behat\Mink\Element\NodeElement | |
1093 | */ | |
1094 | protected function get_management_course_listing_node_by_idnumber($idnumber) { | |
1095 | $id = $this->get_course_id($idnumber); | |
1096 | $selector = sprintf('#course-listing .listitem-course[data-id="%d"] > div', $id); | |
1097 | return $this->find('css', $selector); | |
1098 | } | |
1099 | ||
1100 | /** | |
8aa3aa3d | 1101 | * Clicks on a category in the management interface. |
5dc361e1 | 1102 | * |
8aa3aa3d | 1103 | * @Given /^I click on category "(?P<name>[^"]*)" in the management interface$/ |
5dc361e1 | 1104 | * @param string $name |
5dc361e1 | 1105 | */ |
8aa3aa3d | 1106 | public function i_click_on_category_in_the_management_interface($name) { |
b155a170 SH |
1107 | $node = $this->get_management_category_listing_node_by_name($name, true); |
1108 | $node->click(); | |
5dc361e1 SH |
1109 | } |
1110 | ||
1111 | /** | |
8aa3aa3d | 1112 | * Clicks on a course in the management interface. |
5dc361e1 | 1113 | * |
8aa3aa3d SH |
1114 | * @Given /^I click on course "(?P<name>[^"]*)" in the management interface$/ |
1115 | * @param string $name | |
1116 | */ | |
1117 | public function i_click_on_course_in_the_management_interface($name) { | |
b155a170 SH |
1118 | $node = $this->get_management_course_listing_node_by_name($name, true); |
1119 | $node->click(); | |
8aa3aa3d SH |
1120 | } |
1121 | ||
3b732cd6 | 1122 | /** |
3ea677e3 | 1123 | * Clicks on a category checkbox in the management interface, if not checked. |
3b732cd6 RT |
1124 | * |
1125 | * @Given /^I select category "(?P<name>[^"]*)" in the management interface$/ | |
1126 | * @param string $name | |
1127 | */ | |
1128 | public function i_select_category_in_the_management_interface($name) { | |
1129 | $node = $this->get_management_category_listing_node_by_name($name); | |
3ea677e3 RT |
1130 | $node = $node->findField('bcat[]'); |
1131 | if (!$node->isChecked()) { | |
1132 | $node->click(); | |
1133 | } | |
3b732cd6 RT |
1134 | } |
1135 | ||
1136 | /** | |
3ea677e3 RT |
1137 | * Clicks on a category checkbox in the management interface, if checked. |
1138 | * | |
1139 | * @Given /^I unselect category "(?P<name>[^"]*)" in the management interface$/ | |
1140 | * @param string $name | |
1141 | */ | |
1142 | public function i_unselect_category_in_the_management_interface($name) { | |
1143 | $node = $this->get_management_category_listing_node_by_name($name); | |
1144 | $node = $node->findField('bcat[]'); | |
1145 | if ($node->isChecked()) { | |
1146 | $node->click(); | |
1147 | } | |
1148 | } | |
1149 | ||
1150 | /** | |
1151 | * Clicks course checkbox in the management interface, if not checked. | |
3b732cd6 RT |
1152 | * |
1153 | * @Given /^I select course "(?P<name>[^"]*)" in the management interface$/ | |
1154 | * @param string $name | |
1155 | */ | |
1156 | public function i_select_course_in_the_management_interface($name) { | |
1157 | $node = $this->get_management_course_listing_node_by_name($name); | |
3ea677e3 RT |
1158 | $node = $node->findField('bc[]'); |
1159 | if (!$node->isChecked()) { | |
1160 | $node->click(); | |
1161 | } | |
1162 | } | |
1163 | ||
1164 | /** | |
1165 | * Clicks course checkbox in the management interface, if checked. | |
1166 | * | |
1167 | * @Given /^I unselect course "(?P<name>[^"]*)" in the management interface$/ | |
1168 | * @param string $name | |
1169 | */ | |
1170 | public function i_unselect_course_in_the_management_interface($name) { | |
1171 | $node = $this->get_management_course_listing_node_by_name($name); | |
1172 | $node = $node->findField('bc[]'); | |
1173 | if ($node->isChecked()) { | |
1174 | $node->click(); | |
1175 | } | |
3b732cd6 RT |
1176 | } |
1177 | ||
1178 | /** | |
1179 | * Move selected categories to top level in the management interface. | |
1180 | * | |
3ea677e3 RT |
1181 | * @Given /^I move category "(?P<name>[^"]*)" to top level in the management interface$/ |
1182 | * @param string $name | |
3b732cd6 RT |
1183 | * @return Given[] |
1184 | */ | |
3ea677e3 RT |
1185 | public function i_move_category_to_top_level_in_the_management_interface($name) { |
1186 | $this->i_select_category_in_the_management_interface($name); | |
3b732cd6 RT |
1187 | return array( |
1188 | new Given('I select "' . coursecat::get(0)->get_formatted_name() . '" from "menumovecategoriesto"'), | |
1189 | new Given('I press "bulkmovecategories"'), | |
1190 | ); | |
1191 | } | |
1192 | ||
1193 | /** | |
1194 | * Checks that a category is a subcategory of specific category. | |
1195 | * | |
1196 | * @Given /^I should see category "(?P<subcatidnumber>[^"]*)" as subcategory of "(?P<catidnumber>[^"]*)" in the management interface$/ | |
1197 | * @throws ExpectationException | |
1198 | * @param string $subcatidnumber | |
1199 | * @param string $catidnumber | |
1200 | */ | |
1201 | public function i_should_see_category_as_subcategory_of_in_the_management_interface($subcatidnumber, $catidnumber) { | |
1202 | $categorynodeid = $this->get_category_id($catidnumber); | |
1203 | $subcategoryid = $this->get_category_id($subcatidnumber); | |
1204 | $exception = new ExpectationException('The category '.$subcatidnumber.' is not a subcategory of '.$catidnumber, $this->getSession()); | |
1205 | $selector = sprintf('#category-listing .listitem-category[data-id="%d"] .listitem-category[data-id="%d"]', $categorynodeid, $subcategoryid); | |
1206 | $this->find('css', $selector, $exception); | |
1207 | } | |
1208 | ||
1209 | /** | |
1210 | * Checks that a category is not a subcategory of specific category. | |
1211 | * | |
1212 | * @Given /^I should not see category "(?P<subcatidnumber>[^"]*)" as subcategory of "(?P<catidnumber>[^"]*)" in the management interface$/ | |
1213 | * @throws ExpectationException | |
1214 | * @param string $subcatidnumber | |
1215 | * @param string $catidnumber | |
1216 | */ | |
1217 | public function i_should_not_see_category_as_subcategory_of_in_the_management_interface($subcatidnumber, $catidnumber) { | |
1218 | try { | |
1219 | $this->i_should_see_category_as_subcategory_of_in_the_management_interface($subcatidnumber, $catidnumber); | |
1220 | } catch (ExpectationException $e) { | |
1221 | // ExpectedException means that it is not highlighted. | |
1222 | return; | |
1223 | } | |
1224 | throw new ExpectationException('The category '.$subcatidnumber.' is a subcategory of '.$catidnumber, $this->getSession()); | |
1225 | } | |
1226 | ||
8aa3aa3d SH |
1227 | /** |
1228 | * Click to expand a category revealing its sub categories within the management UI. | |
1229 | * | |
1230 | * @Given /^I click to expand category "(?P<idnumber>[^"]*)" in the management interface$/ | |
5dc361e1 SH |
1231 | * @param string $idnumber |
1232 | */ | |
8aa3aa3d | 1233 | public function i_click_to_expand_category_in_the_management_interface($idnumber) { |
5dc361e1 SH |
1234 | $categorynode = $this->get_management_category_listing_node_by_idnumber($idnumber); |
1235 | $exception = new ExpectationException('Category "' . $idnumber . '" does not contain an expand or collapse toggle.', $this->getSession()); | |
1236 | $togglenode = $this->find('css', 'a[data-action=collapse],a[data-action=expand]', $exception, $categorynode); | |
1237 | $togglenode->click(); | |
1238 | } | |
1239 | ||
1240 | /** | |
8aa3aa3d | 1241 | * Checks that a category within the management interface is visible. |
5dc361e1 SH |
1242 | * |
1243 | * @Given /^category in management listing should be visible "(?P<idnumber>[^"]*)"$/ | |
1244 | * @param string $idnumber | |
1245 | */ | |
1246 | public function category_in_management_listing_should_be_visible($idnumber) { | |
1247 | $id = $this->get_category_id($idnumber); | |
1248 | $exception = new ExpectationException('The category '.$idnumber.' is not visible.', $this->getSession()); | |
1249 | $selector = sprintf('#category-listing .listitem-category[data-id="%d"][data-visible="1"]', $id); | |
1250 | $this->find('css', $selector, $exception); | |
1251 | } | |
1252 | ||
1253 | /** | |
8aa3aa3d | 1254 | * Checks that a category within the management interface is dimmed. |
5dc361e1 SH |
1255 | * |
1256 | * @Given /^category in management listing should be dimmed "(?P<idnumber>[^"]*)"$/ | |
1257 | * @param string $idnumber | |
1258 | */ | |
1259 | public function category_in_management_listing_should_be_dimmed($idnumber) { | |
1260 | $id = $this->get_category_id($idnumber); | |
1261 | $selector = sprintf('#category-listing .listitem-category[data-id="%d"][data-visible="0"]', $id); | |
1262 | $exception = new ExpectationException('The category '.$idnumber.' is visible.', $this->getSession()); | |
1263 | $this->find('css', $selector, $exception); | |
1264 | } | |
1265 | ||
1266 | /** | |
8aa3aa3d | 1267 | * Checks that a course within the management interface is visible. |
5dc361e1 SH |
1268 | * |
1269 | * @Given /^course in management listing should be visible "(?P<idnumber>[^"]*)"$/ | |
1270 | * @param string $idnumber | |
1271 | */ | |
1272 | public function course_in_management_listing_should_be_visible($idnumber) { | |
1273 | $id = $this->get_course_id($idnumber); | |
1274 | $exception = new ExpectationException('The course '.$idnumber.' is not visible.', $this->getSession()); | |
1275 | $selector = sprintf('#course-listing .listitem-course[data-id="%d"][data-visible="1"]', $id); | |
1276 | $this->find('css', $selector, $exception); | |
1277 | } | |
1278 | ||
1279 | /** | |
8aa3aa3d | 1280 | * Checks that a course within the management interface is dimmed. |
5dc361e1 SH |
1281 | * |
1282 | * @Given /^course in management listing should be dimmed "(?P<idnumber>[^"]*)"$/ | |
1283 | * @param string $idnumber | |
1284 | */ | |
1285 | public function course_in_management_listing_should_be_dimmed($idnumber) { | |
1286 | $id = $this->get_course_id($idnumber); | |
1287 | $exception = new ExpectationException('The course '.$idnumber.' is visible.', $this->getSession()); | |
1288 | $selector = sprintf('#course-listing .listitem-course[data-id="%d"][data-visible="0"]', $id); | |
1289 | $this->find('css', $selector, $exception); | |
1290 | } | |
1291 | ||
1292 | /** | |
1293 | * Toggles the visibility of a course in the management UI. | |
1294 | * | |
1295 | * If it was visible it will be hidden. If it is hidden it will be made visible. | |
1296 | * | |
1297 | * @Given /^I toggle visibility of course "(?P<idnumber>[^"]*)" in management listing$/ | |
1298 | * @param string $idnumber | |
1299 | */ | |
1300 | public function i_toggle_visibility_of_course_in_management_listing($idnumber) { | |
1301 | $id = $this->get_course_id($idnumber); | |
1302 | $selector = sprintf('#course-listing .listitem-course[data-id="%d"][data-visible]', $id); | |
1303 | $node = $this->find('css', $selector); | |
1304 | $exception = new ExpectationException('Course listing "' . $idnumber . '" does not contain a show or hide toggle.', $this->getSession()); | |
1305 | if ($node->getAttribute('data-visible') === '1') { | |
1306 | $toggle = $this->find('css', '.action-hide', $exception, $node); | |
1307 | } else { | |
1308 | $toggle = $this->find('css', '.action-show', $exception, $node); | |
1309 | } | |
1310 | $toggle->click(); | |
1311 | } | |
1312 | ||
1313 | /** | |
1314 | * Toggles the visibility of a category in the management UI. | |
1315 | * | |
1316 | * If it was visible it will be hidden. If it is hidden it will be made visible. | |
1317 | * | |
1318 | * @Given /^I toggle visibility of category "(?P<idnumber>[^"]*)" in management listing$/ | |
1319 | */ | |
1320 | public function i_toggle_visibility_of_category_in_management_listing($idnumber) { | |
1321 | $id = $this->get_category_id($idnumber); | |
1322 | $selector = sprintf('#category-listing .listitem-category[data-id="%d"][data-visible]', $id); | |
1323 | $node = $this->find('css', $selector); | |
1324 | $exception = new ExpectationException('Category listing "' . $idnumber . '" does not contain a show or hide toggle.', $this->getSession()); | |
1325 | if ($node->getAttribute('data-visible') === '1') { | |
1326 | $toggle = $this->find('css', '.action-hide', $exception, $node); | |
1327 | } else { | |
1328 | $toggle = $this->find('css', '.action-show', $exception, $node); | |
1329 | } | |
1330 | $toggle->click(); | |
1331 | } | |
1332 | ||
1333 | /** | |
8aa3aa3d SH |
1334 | * Moves a category displayed in the management interface up or down one place. |
1335 | * | |
1336 | * @Given /^I click to move category "(?P<idnumber>[^"]*)" (?P<direction>up|down) one$/ | |
1337 | * | |
1338 | * @param string $idnumber The category idnumber | |
1339 | * @param string $direction The direction to move in, either up or down | |
5dc361e1 | 1340 | */ |
8aa3aa3d SH |
1341 | public function i_click_to_move_category_by_one($idnumber, $direction) { |
1342 | $node = $this->get_management_category_listing_node_by_idnumber($idnumber); | |
1343 | $this->user_moves_listing_by_one('category', $node, $direction); | |
1344 | } | |
1345 | ||
1346 | /** | |
1347 | * Moves a course displayed in the management interface up or down one place. | |
1348 | * | |
1349 | * @Given /^I click to move course "(?P<idnumber>[^"]*)" (?P<direction>up|down) one$/ | |
1350 | * | |
1351 | * @param string $idnumber The course idnumber | |
1352 | * @param string $direction The direction to move in, either up or down | |
1353 | */ | |
1354 | public function i_click_to_move_course_by_one($idnumber, $direction) { | |
1355 | $node = $this->get_management_course_listing_node_by_idnumber($idnumber); | |
1356 | $this->user_moves_listing_by_one('course', $node, $direction); | |
1357 | } | |
1358 | ||
1359 | /** | |
1360 | * Moves a course or category listing within the management interface up or down by one. | |
1361 | * | |
1362 | * @param string $listingtype One of course or category | |
1363 | * @param \Behat\Mink\Element\NodeElement $listingnode | |
1364 | * @param string $direction One of up or down. | |
1365 | * @param bool $highlight If set to false we don't check the node has been highlighted. | |
1366 | */ | |
1367 | protected function user_moves_listing_by_one($listingtype, $listingnode, $direction, $highlight = true) { | |
1368 | $up = (strtolower($direction) === 'up'); | |
5dc361e1 | 1369 | if ($up) { |
8aa3aa3d SH |
1370 | $exception = new ExpectationException($listingtype.' listing does not contain a moveup button.', $this->getSession()); |
1371 | $button = $this->find('css', 'a.action-moveup', $exception, $listingnode); | |
5dc361e1 | 1372 | } else { |
8aa3aa3d SH |
1373 | $exception = new ExpectationException($listingtype.' listing does not contain a movedown button.', $this->getSession()); |
1374 | $button = $this->find('css', 'a.action-movedown', $exception, $listingnode); | |
5dc361e1 SH |
1375 | } |
1376 | $button->click(); | |
8aa3aa3d SH |
1377 | if ($this->running_javascript() && $highlight) { |
1378 | $listitem = $listingnode->getParent(); | |
5dc361e1 SH |
1379 | $exception = new ExpectationException('Nothing was highlighted, ajax didn\'t occur or didn\'t succeed.', $this->getSession()); |
1380 | $this->spin(array($this, 'listing_is_highlighted'), $listitem->getTagName().'#'.$listitem->getAttribute('id'), 2, $exception, true); | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | /** | |
8aa3aa3d SH |
1385 | * Used by spin to determine the callback has been highlighted. |
1386 | * | |
1387 | * @param behat_course $self A self reference (default first arg from a spin callback) | |
1388 | * @param \Behat\Mink\Element\NodeElement $selector | |
1389 | * @return bool | |
5dc361e1 SH |
1390 | */ |
1391 | protected function listing_is_highlighted($self, $selector) { | |
1392 | $listitem = $this->find('css', $selector); | |
1393 | return $listitem->hasClass('highlight'); | |
1394 | } | |
1395 | ||
1396 | /** | |
8aa3aa3d | 1397 | * Check that one course appears before another in the course category management listings. |
5dc361e1 | 1398 | * |
8aa3aa3d SH |
1399 | * @Given /^I should see course listing "(?P<preceedingcourse>[^"]*)" before "(?P<followingcourse>[^"]*)"$/ |
1400 | * | |
1401 | * @param string $preceedingcourse The first course to find | |
1402 | * @param string $followingcourse The second course to find (should be AFTER the first course) | |
1403 | * @throws ExpectationException | |
1404 | */ | |
1405 | public function i_should_see_course_listing_before($preceedingcourse, $followingcourse) { | |
1406 | $xpath = "//div[@id='course-listing']//li[contains(concat(' ', @class, ' '), ' listitem-course ')]//a[text()='{$preceedingcourse}']/ancestor::li[@data-id]//following::a[text()='{$followingcourse}']"; | |
1407 | $msg = "{$preceedingcourse} course does not appear before {$followingcourse} course"; | |
1408 | if (!$this->getSession()->getDriver()->find($xpath)) { | |
1409 | throw new ExpectationException($msg, $this->getSession()); | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | /** | |
1414 | * Check that one category appears before another in the course category management listings. | |
1415 | * | |
1416 | * @Given /^I should see category listing "(?P<preceedingcategory>[^"]*)" before "(?P<followingcategory>[^"]*)"$/ | |
1417 | * | |
1418 | * @param string $preceedingcategory The first category to find | |
1419 | * @param string $followingcategory The second category to find (should be after the first category) | |
1420 | * @throws ExpectationException | |
5dc361e1 | 1421 | */ |
8aa3aa3d SH |
1422 | public function i_should_see_category_listing_before($preceedingcategory, $followingcategory) { |
1423 | $xpath = "//div[@id='category-listing']//li[contains(concat(' ', @class, ' '), ' listitem-category ')]//a[text()='{$preceedingcategory}']/ancestor::li[@data-id]//following::a[text()='{$followingcategory}']"; | |
1424 | $msg = "{$preceedingcategory} category does not appear before {$followingcategory} category"; | |
5dc361e1 SH |
1425 | if (!$this->getSession()->getDriver()->find($xpath)) { |
1426 | throw new ExpectationException($msg, $this->getSession()); | |
1427 | } | |
1428 | } | |
1429 | ||
1430 | /** | |
8aa3aa3d | 1431 | * Checks that we are on the course management page that we expect to be on and that no course has been selected. |
5dc361e1 | 1432 | * |
8aa3aa3d SH |
1433 | * @Given /^I should see the "(?P<mode>[^"]*)" management page$/ |
1434 | * @param string $mode The mode to expected. One of 'Courses', 'Course categories' or 'Course categories and courses' | |
5dc361e1 SH |
1435 | * @return Given[] |
1436 | */ | |
8aa3aa3d | 1437 | public function i_should_see_the_courses_management_page($mode) { |
5dc361e1 SH |
1438 | $return = array( |
1439 | new Given('I should see "Course and category management" in the "h2" "css_element"') | |
1440 | ); | |
1441 | switch ($mode) { | |
1442 | case "Courses": | |
1443 | $return[] = new Given('"#category-listing" "css_element" should not exists'); | |
1444 | $return[] = new Given('"#course-listing" "css_element" should exists'); | |
1445 | break; | |
1446 | case "Course categories": | |
1447 | $return[] = new Given('"#category-listing" "css_element" should exists'); | |
1448 | $return[] = new Given('"#course-listing" "css_element" should not exists'); | |
1449 | break; | |
1450 | case "Courses categories and courses": | |
1451 | default: | |
1452 | $return[] = new Given('"#category-listing" "css_element" should exists'); | |
1453 | $return[] = new Given('"#course-listing" "css_element" should exists'); | |
1454 | break; | |
1455 | } | |
8aa3aa3d | 1456 | $return[] = new Given('"#course-detail" "css_element" should not exists'); |
5dc361e1 SH |
1457 | return $return; |
1458 | } | |
1459 | ||
1460 | /** | |
8aa3aa3d SH |
1461 | * Checks that we are on the course management page that we expect to be on and that a course has been selected. |
1462 | * | |
1463 | * @Given /^I should see the "(?P<mode>[^"]*)" management page with a course selected$/ | |
1464 | * @param string $mode The mode to expected. One of 'Courses', 'Course categories' or 'Course categories and courses' | |
1465 | * @return Given[] | |
5dc361e1 | 1466 | */ |
8aa3aa3d SH |
1467 | public function i_should_see_the_courses_management_page_with_a_course_selected($mode) { |
1468 | $return = $this->i_should_see_the_courses_management_page($mode); | |
1469 | array_pop($return); | |
1470 | $return[] = new Given('"#course-detail" "css_element" should exists'); | |
1471 | return $return; | |
1472 | } | |
1473 | ||
1474 | /** | |
1475 | * Locates a course in the course category management interface and then triggers an action for it. | |
1476 | * | |
1477 | * @Given /^I click on "(?P<action>[^"]*)" action for "(?P<name>[^"]*)" in management course listing$/ | |
1478 | * | |
1479 | * @param string $action The action to take. One of | |
1480 | * @param string $name The name of the course as it is displayed in the management interface. | |
1481 | */ | |
1482 | public function i_click_on_action_for_item_in_management_course_listing($action, $name) { | |
1483 | $node = $this->get_management_course_listing_node_by_name($name); | |
1484 | $this->user_clicks_on_management_listing_action('course', $node, $action); | |
1485 | } | |
1486 | ||
1487 | /** | |
1488 | * Locates a category in the course category management interface and then triggers an action for it. | |
1489 | * | |
1490 | * @Given /^I click on "(?P<action>[^"]*)" action for "(?P<name>[^"]*)" in management category listing$/ | |
1491 | * | |
1492 | * @param string $action The action to take. One of | |
1493 | * @param string $name The name of the category as it is displayed in the management interface. | |
1494 | */ | |
1495 | public function i_click_on_action_for_item_in_management_category_listing($action, $name) { | |
1496 | $node = $this->get_management_category_listing_node_by_name($name); | |
1497 | $this->user_clicks_on_management_listing_action('category', $node, $action); | |
1498 | } | |
1499 | ||
32fcea74 DM |
1500 | /** |
1501 | * Clicks to expand or collapse a category displayed on the frontpage | |
1502 | * | |
1503 | * @Given /^I toggle "(?P<categoryname_string>(?:[^"]|\\")*)" category children visibility in frontpage$/ | |
1504 | * @throws ExpectationException | |
1505 | * @param string $categoryname | |
1506 | */ | |
1507 | public function i_toggle_category_children_visibility_in_frontpage($categoryname) { | |
1508 | ||
1509 | $headingtags = array(); | |
1510 | for ($i = 1; $i <= 6; $i++) { | |
1511 | $headingtags[] = 'self::h' . $i; | |
1512 | } | |
1513 | ||
1514 | $exception = new ExpectationException('"' . $categoryname . '" category can not be found', $this->getSession()); | |
1515 | $categoryliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($categoryname); | |
1516 | $xpath = "//div[@class='info']/descendant::*[" . implode(' or ', $headingtags) . "][@class='categoryname'][./descendant::a[.=$categoryliteral]]"; | |
1517 | $node = $this->find('xpath', $xpath, $exception); | |
1518 | $node->click(); | |
1519 | ||
1520 | // Smooth expansion. | |
1521 | $this->getSession()->wait(1000, false); | |
1522 | } | |
1523 | ||
8aa3aa3d SH |
1524 | /** |
1525 | * Finds the node to use for a management listitem action and clicks it. | |
1526 | * | |
1527 | * @param string $listingtype Either course or category. | |
1528 | * @param \Behat\Mink\Element\NodeElement $listingnode | |
1529 | * @param string $action The action being taken | |
1530 | * @throws Behat\Mink\Exception\ExpectationException | |
1531 | */ | |
1532 | protected function user_clicks_on_management_listing_action($listingtype, $listingnode, $action) { | |
1533 | $actionsnode = $listingnode->find('xpath', "//*[contains(concat(' ', normalize-space(@class), ' '), '{$listingtype}-item-actions')]"); | |
5dc361e1 | 1534 | if (!$actionsnode) { |
8aa3aa3d | 1535 | throw new ExpectationException("Could not find the actions for $listingtype", $this->getSession()); |
5dc361e1 SH |
1536 | } |
1537 | $actionnode = $actionsnode->find('css', '.action-'.$action); | |
5dc361e1 SH |
1538 | if (!$actionnode) { |
1539 | throw new ExpectationException("Expected action was not available or not found ($action)", $this->getSession()); | |
1540 | } | |
cda49969 SH |
1541 | if ($this->running_javascript() && !$actionnode->isVisible()) { |
1542 | $actionsnode->find('css', 'a.toggle-display')->click(); | |
1543 | $actionnode = $actionsnode->find('css', '.action-'.$action); | |
1544 | } | |
5dc361e1 SH |
1545 | $actionnode->click(); |
1546 | } | |
d0647301 SH |
1547 | |
1548 | /** | |
1549 | * Clicks on a category in the management interface. | |
1550 | * | |
1551 | * @Given /^I click on "([^"]*)" category in the management category listing$/ | |
1552 | * @param string $name The name of the category to click. | |
1553 | */ | |
1554 | public function i_click_on_category_in_the_management_category_listing($name) { | |
1555 | $node = $this->get_management_category_listing_node_by_name($name); | |
1556 | $node->find('css', 'a.categoryname')->click(); | |
1557 | } | |
a1990e50 | 1558 | } |