Merge branch '42246-26' of git://github.com/samhemelryk/moodle
[moodle.git] / course / tests / behat / behat_course.php
CommitLineData
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
28require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
29
30use 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 */
44class 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) {
70 return array(
71 new Given('I go to the courses management page'),
8aa3aa3d
SH
72 new Given('I should see the "'.get_string('categories').'" management page'),
73 new Given('I click on category "'.get_string('miscellaneous').'" in the management interface'),
74 new Given('I should see the "'.get_string('categoriesandcoures').'" management page'),
75 new Given('I click on "'.get_string('newcourse').'" "link" in the "#course-listing" "css_element"'),
df1ff55d 76 new Given('I fill the moodle form with:', $table),
dedb9738 77 new Given('I press "' . get_string('savechanges') . '"')
df1ff55d
DM
78 );
79 }
80
81 /**
82 * Goes to the system courses/categories management page.
83 *
84 * @Given /^I go to the courses management page$/
5dc361e1 85 * @return Given[]
df1ff55d
DM
86 */
87 public function i_go_to_the_courses_management_page() {
88
89 return array(
90 new Given('I am on homepage'),
dedb9738
DM
91 new Given('I expand "' . get_string('administrationsite') . '" node'),
92 new Given('I expand "' . get_string('courses', 'admin') . '" node'),
93 new Given('I follow "' . get_string('coursemgmt', 'admin') . '"'),
df1ff55d
DM
94 );
95 }
96
a1990e50
DM
97 /**
98 * Adds the selected activity/resource filling the form data with the specified field/value pairs.
99 *
44d5af38 100 * @When /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)" and I fill the form with:$/
a1990e50 101 * @param string $activity The activity name
0e575f01 102 * @param int $section The section number
a1990e50 103 * @param TableNode $data The activity field/value data
5dc361e1 104 * @return Given[]
a1990e50
DM
105 */
106 public function i_add_to_section_and_i_fill_the_form_with($activity, $section, TableNode $data) {
107
a1990e50 108 return array(
38976081 109 new Given('I add a "' . $this->escape($activity) . '" to section "' . $this->escape($section) . '"'),
a1990e50 110 new Given('I fill the moodle form with:', $data),
dedb9738 111 new Given('I press "' . get_string('savechangesandreturntocourse') . '"')
a1990e50
DM
112 );
113 }
114
115 /**
116 * Opens the activity chooser and opens the activity/resource form page.
117 *
44d5af38 118 * @Given /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)"$/
1f9ffbdb 119 * @throws ElementNotFoundException Thrown by behat_base::find
a1990e50 120 * @param string $activity
0e575f01 121 * @param int $section
a1990e50
DM
122 */
123 public function i_add_to_section($activity, $section) {
124
38976081
DM
125 $sectionxpath = "//li[@id='section-" . $section . "']";
126
127 $activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral(ucfirst($activity));
1c00d6f6
DM
128
129 if ($this->running_javascript()) {
130
131 // Clicks add activity or resource section link.
132 $sectionxpath = $sectionxpath . "/descendant::div[@class='section-modchooser']/span/a";
133 $sectionnode = $this->find('xpath', $sectionxpath);
134 $sectionnode->click();
135
136 // Clicks the selected activity if it exists.
00ea74cb 137 $activityxpath = "//div[@id='chooseform']/descendant::label" .
38976081
DM
138 "/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
139 "[contains(., $activityliteral)]" .
00ea74cb 140 "/parent::label/child::input";
1c00d6f6
DM
141 $activitynode = $this->find('xpath', $activityxpath);
142 $activitynode->doubleClick();
143
144 } else {
145 // Without Javascript.
146
147 // Selecting the option from the select box which contains the option.
38976081
DM
148 $selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
149 "/descendant::select[contains(., $activityliteral)]";
1c00d6f6
DM
150 $selectnode = $this->find('xpath', $selectxpath);
151 $selectnode->selectOption($activity);
152
153 // Go button.
154 $gobuttonxpath = $selectxpath . "/ancestor::form/descendant::input[@type='submit']";
155 $gobutton = $this->find('xpath', $gobuttonxpath);
156 $gobutton->click();
157 }
158
a1990e50
DM
159 }
160
18c84063
DM
161 /**
162 * Turns course section highlighting on.
163 *
164 * @Given /^I turn section "(?P<section_number>\d+)" highlighting on$/
165 * @param int $sectionnumber The section number
5dc361e1 166 * @return Given[]
18c84063
DM
167 */
168 public function i_turn_section_highlighting_on($sectionnumber) {
169
170 // Ensures the section exists.
171 $xpath = $this->section_exists($sectionnumber);
172
173 return array(
38976081 174 new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
18c84063
DM
175 new Given('I wait "2" seconds')
176 );
177 }
178
179 /**
180 * Turns course section highlighting off.
181 *
182 * @Given /^I turn section "(?P<section_number>\d+)" highlighting off$/
183 * @param int $sectionnumber The section number
5dc361e1 184 * @return Given[]
18c84063
DM
185 */
186 public function i_turn_section_highlighting_off($sectionnumber) {
187
188 // Ensures the section exists.
189 $xpath = $this->section_exists($sectionnumber);
190
191 return array(
38976081 192 new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
18c84063
DM
193 new Given('I wait "2" seconds')
194 );
195 }
196
197 /**
b918f9f7
DM
198 * Shows the specified hidden section. You need to be in the course page and on editing mode.
199 *
200 * @Given /^I show section "(?P<section_number>\d+)"$/
201 * @param int $sectionnumber
202 */
203 public function i_show_section($sectionnumber) {
0e575f01
DM
204 $showlink = $this->show_section_icon_exists($sectionnumber);
205 $showlink->click();
b918f9f7
DM
206
207 // It requires time.
0e575f01
DM
208 if ($this->running_javascript()) {
209 $this->getSession()->wait(5000, false);
210 }
b918f9f7
DM
211 }
212
213 /**
214 * Hides the specified visible section. You need to be in the course page and on editing mode.
215 *
216 * @Given /^I hide section "(?P<section_number>\d+)"$/
217 * @param int $sectionnumber
218 */
219 public function i_hide_section($sectionnumber) {
0e575f01
DM
220 $hidelink = $this->hide_section_icon_exists($sectionnumber);
221 $hidelink->click();
b918f9f7
DM
222
223 // It requires time.
0e575f01
DM
224 if ($this->running_javascript()) {
225 $this->getSession()->wait(5000, false);
226 }
b918f9f7
DM
227 }
228
229 /**
230 * Checks if the specified course section hightlighting is turned on. You need to be in the course page on editing mode.
18c84063 231 *
18c84063 232 * @Then /^section "(?P<section_number>\d+)" should be highlighted$/
b918f9f7 233 * @throws ExpectationException
18c84063
DM
234 * @param int $sectionnumber The section number
235 */
236 public function section_should_be_highlighted($sectionnumber) {
237
238 // Ensures the section exists.
239 $xpath = $this->section_exists($sectionnumber);
240
241 // The important checking, we can not check the img.
242 $xpath = $xpath . "/descendant::img[@alt='" . get_string('markedthistopic') . "'][contains(@src, 'marked')]";
243 $exception = new ExpectationException('The "' . $sectionnumber . '" section is not highlighted', $this->getSession());
244 $this->find('xpath', $xpath, $exception);
245 }
246
247 /**
b918f9f7 248 * Checks if the specified course section highlighting is turned off. You need to be in the course page on editing mode.
18c84063
DM
249 *
250 * @Then /^section "(?P<section_number>\d+)" should not be highlighted$/
b918f9f7 251 * @throws ExpectationException
18c84063
DM
252 * @param int $sectionnumber The section number
253 */
254 public function section_should_not_be_highlighted($sectionnumber) {
255
256 // We only catch ExpectationException, ElementNotFoundException should be thrown if the specified section does not exist.
257 try {
258 $this->section_should_be_highlighted($sectionnumber);
259 } catch (ExpectationException $e) {
260 // ExpectedException means that it is not highlighted.
261 return;
262 }
263
264 throw new ExpectationException('The "' . $sectionnumber . '" section is highlighted', $this->getSession());
265 }
266
b918f9f7
DM
267 /**
268 * 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.
269 *
270 * @Then /^section "(?P<section_number>\d+)" should be hidden$/
271 * @throws ExpectationException
272 * @throws ElementNotFoundException Thrown by behat_base::find
273 * @param int $sectionnumber
274 */
275 public function section_should_be_hidden($sectionnumber) {
276
277 $sectionxpath = $this->section_exists($sectionnumber);
278
279 // Section should be hidden.
280 $exception = new ExpectationException('The section is not hidden', $this->getSession());
38976081 281 $this->find('xpath', $sectionxpath . "[contains(concat(' ', normalize-space(@class), ' '), ' hidden ')]", $exception);
b918f9f7
DM
282
283 // The checking are different depending on user permissions.
284 if ($this->is_course_editor()) {
285
286 // The section must be hidden.
287 $this->show_section_icon_exists($sectionnumber);
288
289 // If there are activities they should be hidden and the visibility icon should not be available.
290 if ($activities = $this->get_section_activities($sectionxpath)) {
291
292 $dimmedexception = new ExpectationException('There are activities that are not dimmed', $this->getSession());
293 $visibilityexception = new ExpectationException('There are activities which visibility icons are clickable', $this->getSession());
294 foreach ($activities as $activity) {
295
296 // Dimmed.
38976081
DM
297 $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' activityinstance ')]" .
298 "/a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity);
b918f9f7 299
0e575f01
DM
300 // Non-JS browsers can not click on img elements.
301 if ($this->running_javascript()) {
302 // To check that the visibility is not clickable we check the funcionality rather than the applied style.
303 $visibilityiconnode = $this->find('css', 'a.editing_show img', false, $activity);
304 $visibilityiconnode->click();
305 }
b918f9f7
DM
306
307 // We ensure that we still see the show icon.
308 $visibilityiconnode = $this->find('css', 'a.editing_show img', $visibilityexception, $activity);
309 }
310 }
311
312 } else {
313 // There shouldn't be activities.
314 if ($this->get_section_activities($sectionxpath)) {
315 throw new ExpectationException('There are activities in the section and they should be hidden', $this->getSession());
316 }
317 }
318 }
319
320 /**
321 * 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.
322 *
323 * @Then /^section "(?P<section_number>\d+)" should be visible$/
324 * @throws ExpectationException
325 * @param int $sectionnumber
326 */
327 public function section_should_be_visible($sectionnumber) {
328
329 $sectionxpath = $this->section_exists($sectionnumber);
330
331 // Section should not be hidden.
38976081
DM
332 $xpath = $sectionxpath . "[not(contains(concat(' ', normalize-space(@class), ' '), ' hidden '))]";
333 if (!$this->getSession()->getPage()->find('xpath', $xpath)) {
b918f9f7
DM
334 throw new ExpectationException('The section is hidden', $this->getSession());
335 }
336
337 // Hide section button should be visible.
338 if ($this->is_course_editor()) {
339 $this->hide_section_icon_exists($sectionnumber);
340 }
341 }
342
0e575f01
DM
343 /**
344 * Moves up the specified section, this step only works with Javascript disabled. Editing mode should be on.
345 *
346 * @Given /^I move up section "(?P<section_number>\d+)"$/
347 * @throws DriverException Step not available when Javascript is enabled
348 * @param int $sectionnumber
349 */
350 public function i_move_up_section($sectionnumber) {
351
352 if ($this->running_javascript()) {
353 throw new DriverException('Move a section up step is not available with Javascript enabled');
354 }
355
356 // Ensures the section exists.
357 $sectionxpath = $this->section_exists($sectionnumber);
358
359 // Follows the link
360 $moveuplink = $this->get_node_in_container('link', get_string('moveup'), 'xpath_element', $sectionxpath);
361 $moveuplink->click();
362 }
363
364 /**
365 * Moves down the specified section, this step only works with Javascript disabled. Editing mode should be on.
366 *
367 * @Given /^I move down section "(?P<section_number>\d+)"$/
368 * @throws DriverException Step not available when Javascript is enabled
369 * @param int $sectionnumber
370 */
371 public function i_move_down_section($sectionnumber) {
372
373 if ($this->running_javascript()) {
374 throw new DriverException('Move a section down step is not available with Javascript enabled');
375 }
376
377 // Ensures the section exists.
378 $sectionxpath = $this->section_exists($sectionnumber);
379
380 // Follows the link
381 $movedownlink = $this->get_node_in_container('link', get_string('movedown'), 'xpath_element', $sectionxpath);
382 $movedownlink->click();
383 }
384
bf648567
DM
385 /**
386 * 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.
387 *
388 * @Then /^"(?P<activity_or_resource_string>(?:[^"]|\\")*)" activity should be visible$/
389 * @param string $activityname
5dc361e1 390 * @throws ExpectationException
bf648567
DM
391 */
392 public function activity_should_be_visible($activityname) {
393
394 // The activity must exists and be visible.
395 $activitynode = $this->get_activity_node($activityname);
396
397 if ($this->is_course_editor()) {
398
399 // The activity should not be dimmed.
400 try {
401 $this->find('css', 'a.dimmed', false, $activitynode);
402 throw new ExpectationException('"' . $activityname . '" is hidden', $this->getSession());
403 } catch (ElementNotFoundException $e) {
404 // All ok.
405 }
406
407 // The 'Hide' button should be available.
408 $nohideexception = new ExpectationException('"' . $activityname . '" don\'t have a "' . get_string('hide') . '" icon', $this->getSession());
409 $this->find('named', array('link', get_string('hide')), $nohideexception, $activitynode);
410 }
411 }
412
413 /**
414 * 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.
415 *
416 * @Then /^"(?P<activity_or_resource_string>(?:[^"]|\\")*)" activity should be hidden$/
417 * @param string $activityname
5dc361e1 418 * @throws ExpectationException
bf648567
DM
419 */
420 public function activity_should_be_hidden($activityname) {
421
422 if ($this->is_course_editor()) {
423
424 // The activity should exists.
425 $activitynode = $this->get_activity_node($activityname);
426
427 // Should be hidden.
428 $exception = new ExpectationException('"' . $activityname . '" is not dimmed', $this->getSession());
429 $this->find('css', 'a.dimmed', $exception, $activitynode);
430
431 // Also 'Show' icon.
432 $noshowexception = new ExpectationException('"' . $activityname . '" don\'t have a "' . get_string('show') . '" icon', $this->getSession());
433 $this->find('named', array('link', get_string('show')), $noshowexception, $activitynode);
434
435 } else {
436
437 // It should not exists at all.
438 try {
439 $this->find_link($activityname);
440 throw new ExpectationException('The "' . $activityname . '" should not appear');
441 } catch (ElementNotFoundException $e) {
442 // This is good, the activity should not be there.
443 }
444 }
445
446 }
447
0e575f01 448 /**
7daab401 449 * 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
450 *
451 * @Given /^I move "(?P<activity_name_string>(?:[^"]|\\")*)" activity to section "(?P<section_number>\d+)"$/
452 * @param string $activityname The activity name
453 * @param int $sectionnumber The number of section
5dc361e1 454 * @return Given[]
0e575f01
DM
455 */
456 public function i_move_activity_to_section($activityname, $sectionnumber) {
457
458 // Ensure the destination is valid.
459 $sectionxpath = $this->section_exists($sectionnumber);
460
461 $activitynode = $this->get_activity_element('.editing_move img', 'css_element', $activityname);
462
463 // JS enabled.
464 if ($this->running_javascript()) {
465
38976081 466 $destinationxpath = $sectionxpath . "/descendant::ul[contains(concat(' ', normalize-space(@class), ' '), ' yui3-dd-drop ')]";
0e575f01
DM
467
468 return array(
38976081
DM
469 new Given('I drag "' . $this->escape($activitynode->getXpath()) . '" "xpath_element" ' .
470 'and I drop it in "' . $this->escape($destinationxpath) . '" "xpath_element"'),
0e575f01
DM
471 );
472
473 } else {
474 // Following links with no-JS.
475
476 // Moving to the fist spot of the section (before all other section's activities).
477 return array(
38976081
DM
478 new Given('I click on "a.editing_move" "css_element" in the "' . $this->escape($activityname) . '" activity'),
479 new Given('I click on "li.movehere a" "css_element" in the "' . $this->escape($sectionxpath) . '" "xpath_element"'),
0e575f01
DM
480 );
481 }
482 }
483
484 /**
485 * Edits the activity name through the edit activity; this step only works with Javascript enabled. Editing mode should be on.
486 *
487 * @Given /^I change "(?P<activity_name_string>(?:[^"]|\\")*)" activity name to "(?P<new_name_string>(?:[^"]|\\")*)"$/
488 * @throws DriverException Step not available when Javascript is disabled
489 * @param string $activityname
490 * @param string $newactivityname
5dc361e1 491 * @return Given[]
0e575f01
DM
492 */
493 public function i_change_activity_name_to($activityname, $newactivityname) {
494
495 if (!$this->running_javascript()) {
496 throw new DriverException('Change activity name step is not available with Javascript disabled');
497 }
498
499 // Adding chr(10) to save changes.
e5de4933 500 $activity = $this->escape($activityname);
0e575f01 501 return array(
e5de4933
SH
502 new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity'),
503 new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $activity .'" activity'),
38976081 504 new Given('I fill in "title" with "' . $this->escape($newactivityname) . chr(10) . '"'),
0e575f01
DM
505 new Given('I wait "2" seconds')
506 );
507 }
508
509 /**
510 * Indents to the right the activity or resource specified by it's name. Editing mode should be on.
511 *
512 * @Given /^I indent right "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
513 * @param string $activityname
5dc361e1 514 * @return Given[]
0e575f01
DM
515 */
516 public function i_indent_right_activity($activityname) {
517
e5de4933
SH
518 $steps = array();
519 $activity = $this->escape($activityname);
520 if ($this->running_javascript()) {
521 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
522 }
523 $steps[] = new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $activity . '" activity');
0e575f01
DM
524
525 if ($this->running_javascript()) {
526 $steps[] = new Given('I wait "2" seconds');
527 }
528
529 return $steps;
530 }
531
532 /**
533 * Indents to the left the activity or resource specified by it's name. Editing mode should be on.
534 *
535 * @Given /^I indent left "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
536 * @param string $activityname
5dc361e1 537 * @return Given[]
0e575f01
DM
538 */
539 public function i_indent_left_activity($activityname) {
540
e5de4933
SH
541 $steps = array();
542 $activity = $this->escape($activityname);
543 if ($this->running_javascript()) {
544 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
545 }
546 $steps[] = new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $activity . '" activity');
0e575f01
DM
547
548 if ($this->running_javascript()) {
549 $steps[] = new Given('I wait "2" seconds');
550 }
551
552 return $steps;
553
554 }
555
556 /**
7daab401 557 * 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
558 *
559 * @Given /^I delete "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
560 * @param string $activityname
5dc361e1 561 * @return Given[]
0e575f01
DM
562 */
563 public function i_delete_activity($activityname) {
564
565 $deletestring = get_string('delete');
566
567 // JS enabled.
568 // Not using chain steps here because the exceptions catcher have problems detecting
569 // JS modal windows and avoiding interacting them at the same time.
570 if ($this->running_javascript()) {
571
572 $element = $this->get_activity_element($deletestring, 'link', $activityname);
573 $element->click();
574
575 $this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
576
577 $this->getSession()->wait(2 * 1000, false);
578
579 } else {
580
581 // With JS disabled.
582 $steps = array(
38976081 583 new Given('I click on "' . $this->escape($deletestring) . '" "link" in the "' . $this->escape($activityname) . '" activity'),
0e575f01
DM
584 new Given('I press "' . get_string('yes') . '"')
585 );
586
587 return $steps;
588 }
589 }
590
591 /**
592 * Duplicates the activity or resource specified by it's name. You should be in the course page with editing mode on.
593 *
594 * @Given /^I duplicate "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
595 * @param string $activityname
5dc361e1 596 * @return Given[]
0e575f01
DM
597 */
598 public function i_duplicate_activity($activityname) {
e5de4933
SH
599 $steps = array();
600 $activity = $this->escape($activityname);
601 if ($this->running_javascript()) {
602 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
603 }
604 $steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
605 $steps[] = new Given('I press "' . get_string('continue') .'"');
606 $steps[] = new Given('I press "' . get_string('duplicatecontcourse') .'"');
607 return $steps;
0e575f01
DM
608 }
609
610 /**
611 * 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.
612 *
613 * @Given /^I duplicate "(?P<activity_name_string>(?:[^"]|\\")*)" activity editing the new copy with:$/
614 * @param string $activityname
615 * @param TableNode $data
5dc361e1 616 * @return Given[]
0e575f01
DM
617 */
618 public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) {
e5de4933
SH
619 $steps = array();
620 $activity = $this->escape($activityname);
621 if ($this->running_javascript()) {
622 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
623 }
624 $steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
625 $steps[] = new Given('I press "' . get_string('continue') .'"');
626 $steps[] = new Given('I press "' . get_string('duplicatecontedit') . '"');
627 $steps[] = new Given('I fill the moodle form with:', $data);
628 $steps[] = new Given('I press "' . get_string('savechangesandreturntocourse') . '"');
629 return $steps;
0e575f01
DM
630 }
631
632 /**
633 * Clicks on the specified element of the activity. You should be in the course page with editing mode turned on.
634 *
635 * @Given /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<activity_name_string>[^"]*)" activity$/
636 * @param string $element
637 * @param string $selectortype
638 * @param string $activityname
639 */
640 public function i_click_on_in_the_activity($element, $selectortype, $activityname) {
641 $element = $this->get_activity_element($element, $selectortype, $activityname);
642 $element->click();
643 }
644
645 /**
646 * Clicks on the specified element inside the activity container.
647 *
648 * @throws ElementNotFoundException
649 * @param string $element
650 * @param string $selectortype
651 * @param string $activityname
652 * @return NodeElement
653 */
654 protected function get_activity_element($element, $selectortype, $activityname) {
655 $activitynode = $this->get_activity_node($activityname);
656
657 // Transforming to Behat selector/locator.
658 list($selector, $locator) = $this->transform_selector($selectortype, $element);
659 $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . $selectortype . '" in "' . $activityname . '" ');
660
661 return $this->find($selector, $locator, $exception, $activitynode);
662 }
663
18c84063
DM
664 /**
665 * Checks if the course section exists.
666 *
667 * @throws ElementNotFoundException Thrown by behat_base::find
668 * @param int $sectionnumber
b918f9f7 669 * @return string The xpath of the section.
18c84063
DM
670 */
671 protected function section_exists($sectionnumber) {
672
673 // Just to give more info in case it does not exist.
674 $xpath = "//li[@id='section-" . $sectionnumber . "']";
675 $exception = new ElementNotFoundException($this->getSession(), "Section $sectionnumber ");
676 $this->find('xpath', $xpath, $exception);
677
678 return $xpath;
679 }
b918f9f7
DM
680
681 /**
682 * Returns the show section icon or throws an exception.
683 *
684 * @throws ElementNotFoundException Thrown by behat_base::find
685 * @param int $sectionnumber
686 * @return NodeElement
687 */
688 protected function show_section_icon_exists($sectionnumber) {
689
690 // Gets the section xpath and ensure it exists.
691 $xpath = $this->section_exists($sectionnumber);
692
693 // We need to know the course format as the text strings depends on them.
694 $courseformat = $this->get_course_format();
695
696 // Checking the show button alt text and show icon.
38976081
DM
697 $showtext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('showfromothers', $courseformat));
698 $linkxpath = $xpath . "/descendant::a[@title=$showtext]";
699 $imgxpath = $linkxpath . "/descendant::img[@alt=$showtext][contains(@src, 'show')]";
b918f9f7
DM
700
701 $exception = new ElementNotFoundException($this->getSession(), 'Show section icon ');
0e575f01
DM
702 $this->find('xpath', $imgxpath, $exception);
703
704 // Returing the link so both Non-JS and JS browsers can interact with it.
705 return $this->find('xpath', $linkxpath, $exception);
b918f9f7
DM
706 }
707
708 /**
709 * Returns the hide section icon link if it exists or throws exception.
710 *
711 * @throws ElementNotFoundException Thrown by behat_base::find
712 * @param int $sectionnumber
713 * @return NodeElement
714 */
715 protected function hide_section_icon_exists($sectionnumber) {
716
717 // Gets the section xpath and ensure it exists.
718 $xpath = $this->section_exists($sectionnumber);
719
720 // We need to know the course format as the text strings depends on them.
721 $courseformat = $this->get_course_format();
722
723 // Checking the hide button alt text and hide icon.
38976081
DM
724 $hidetext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('hidefromothers', $courseformat));
725 $linkxpath = $xpath . "/descendant::a[@title=$hidetext]";
726 $imgxpath = $linkxpath . "/descendant::img[@alt=$hidetext][contains(@src, 'hide')]";
b918f9f7
DM
727
728 $exception = new ElementNotFoundException($this->getSession(), 'Hide section icon ');
0e575f01
DM
729 $this->find('xpath', $imgxpath, $exception);
730
731 // Returing the link so both Non-JS and JS browsers can interact with it.
732 return $this->find('xpath', $linkxpath, $exception);
b918f9f7
DM
733 }
734
735 /**
736 * Gets the current course format.
737 *
738 * @throws ExpectationException If we are not in the course view page.
739 * @return string The course format in a frankenstyled name.
740 */
741 protected function get_course_format() {
742
743 $exception = new ExpectationException('You are not in a course page', $this->getSession());
744
745 // The moodle body's id attribute contains the course format.
746 $node = $this->getSession()->getPage()->find('css', 'body');
747 if (!$node) {
748 throw $exception;
749 }
750
751 if (!$bodyid = $node->getAttribute('id')) {
752 throw $exception;
753 }
754
755 if (strstr($bodyid, 'page-course-view-') === false) {
756 throw $exception;
757 }
758
759 return 'format_' . str_replace('page-course-view-', '', $bodyid);
760 }
761
762 /**
763 * Gets the section's activites DOM nodes.
764 *
765 * @param string $sectionxpath
766 * @return array NodeElement instances
767 */
768 protected function get_section_activities($sectionxpath) {
769
38976081 770 $xpath = $sectionxpath . "/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]";
b918f9f7
DM
771
772 // We spin here, as activities usually require a lot of time to load.
773 try {
774 $activities = $this->find_all('xpath', $xpath);
775 } catch (ElementNotFoundException $e) {
776 return false;
777 }
778
779 return $activities;
780 }
781
bf648567
DM
782 /**
783 * Returns the DOM node of the activity from <li>.
784 *
785 * @throws ElementNotFoundException Thrown by behat_base::find
786 * @param string $activityname The activity name
787 * @return NodeElement
788 */
789 protected function get_activity_node($activityname) {
790
38976081
DM
791 $activityname = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname);
792 $xpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityname)]";
bf648567
DM
793
794 return $this->find('xpath', $xpath);
795 }
796
b918f9f7
DM
797 /**
798 * Returns whether the user can edit the course contents or not.
799 *
800 * @return bool
801 */
802 protected function is_course_editor() {
803
804 // We don't need to behat_base::spin() here as all is already loaded.
dedb9738
DM
805 if (!$this->getSession()->getPage()->findButton(get_string('turneditingoff')) &&
806 !$this->getSession()->getPage()->findButton(get_string('turneditingon'))) {
b918f9f7
DM
807 return false;
808 }
809
810 return true;
811 }
812
5dc361e1
SH
813 /**
814 * Returns the id of the category with the given idnumber.
8aa3aa3d
SH
815 *
816 * Please note that this function requires the category to exist. If it does not exist an ExpectationException is thrown.
817 *
5dc361e1
SH
818 * @param string $idnumber
819 * @return string
8aa3aa3d 820 * @throws ExpectationException
5dc361e1
SH
821 */
822 protected function get_category_id($idnumber) {
823 global $DB;
8aa3aa3d
SH
824 try {
825 return $DB->get_field('course_categories', 'id', array('idnumber' => $idnumber), MUST_EXIST);
826 } catch (dml_missing_record_exception $ex) {
827 throw new ExpectationException(sprintf("There is no category in the database with the idnumber '%s'", $idnumber));
828 }
5dc361e1
SH
829 }
830
831 /**
832 * Returns the id of the course with the given idnumber.
8aa3aa3d
SH
833 *
834 * Please note that this function requires the category to exist. If it does not exist an ExpectationException is thrown.
835 *
5dc361e1
SH
836 * @param string $idnumber
837 * @return string
8aa3aa3d 838 * @throws ExpectationException
5dc361e1
SH
839 */
840 protected function get_course_id($idnumber) {
841 global $DB;
8aa3aa3d
SH
842 try {
843 return $DB->get_field('course', 'id', array('idnumber' => $idnumber), MUST_EXIST);
844 } catch (dml_missing_record_exception $ex) {
845 throw new ExpectationException(sprintf("There is no course in the database with the idnumber '%s'", $idnumber));
846 }
5dc361e1
SH
847 }
848
849 /**
850 * Returns the category node from within the listing on the management page.
851 *
852 * @param string $idnumber
853 * @return \Behat\Mink\Element\NodeElement
854 */
855 protected function get_management_category_listing_node_by_idnumber($idnumber) {
856 $id = $this->get_category_id($idnumber);
857 $selector = sprintf('#category-listing .listitem-category[data-id="%d"] > div', $id);
858 return $this->find('css', $selector);
859 }
860
861 /**
8aa3aa3d
SH
862 * Returns a category node from within the management interface.
863 *
864 * @param string $name The name of the category.
b155a170 865 * @param bool $link If set to true we'll resolve to the link rather than just the node.
5dc361e1
SH
866 * @return \Behat\Mink\Element\NodeElement
867 */
b155a170
SH
868 protected function get_management_category_listing_node_by_name($name, $link = false) {
869 $selector = "//div[@id='category-listing']//li[contains(concat(' ', normalize-space(@class), ' '), ' listitem-category ')]//a[text()='{$name}']";
870 if ($link === false) {
871 $selector .= "/ancestor::li[@data-id]";
872 }
5dc361e1
SH
873 return $this->find('xpath', $selector);
874 }
875
876 /**
8aa3aa3d
SH
877 * Returns a course node from within the management interface.
878 *
879 * @param string $name The name of the course.
b155a170 880 * @param bool $link If set to true we'll resolve to the link rather than just the node.
5dc361e1
SH
881 * @return \Behat\Mink\Element\NodeElement
882 */
b155a170
SH
883 protected function get_management_course_listing_node_by_name($name, $link = false) {
884 $selector = "//div[@id='course-listing']//li[contains(concat(' ', @class, ' '), ' listitem-course ')]//a[text()='{$name}']";
885 if ($link === false) {
886 $selector .= "/ancestor::li[@data-id]";
887 }
5dc361e1
SH
888 return $this->find('xpath', $selector);
889 }
890
891 /**
892 * Returns the course node from within the listing on the management page.
893 *
894 * @param string $idnumber
895 * @return \Behat\Mink\Element\NodeElement
896 */
897 protected function get_management_course_listing_node_by_idnumber($idnumber) {
898 $id = $this->get_course_id($idnumber);
899 $selector = sprintf('#course-listing .listitem-course[data-id="%d"] > div', $id);
900 return $this->find('css', $selector);
901 }
902
903 /**
8aa3aa3d 904 * Clicks on a category in the management interface.
5dc361e1 905 *
8aa3aa3d 906 * @Given /^I click on category "(?P<name>[^"]*)" in the management interface$/
5dc361e1 907 * @param string $name
5dc361e1 908 */
8aa3aa3d 909 public function i_click_on_category_in_the_management_interface($name) {
b155a170
SH
910 $node = $this->get_management_category_listing_node_by_name($name, true);
911 $node->click();
5dc361e1
SH
912 }
913
914 /**
8aa3aa3d 915 * Clicks on a course in the management interface.
5dc361e1 916 *
8aa3aa3d
SH
917 * @Given /^I click on course "(?P<name>[^"]*)" in the management interface$/
918 * @param string $name
919 */
920 public function i_click_on_course_in_the_management_interface($name) {
b155a170
SH
921 $node = $this->get_management_course_listing_node_by_name($name, true);
922 $node->click();
8aa3aa3d
SH
923 }
924
925 /**
926 * Click to expand a category revealing its sub categories within the management UI.
927 *
928 * @Given /^I click to expand category "(?P<idnumber>[^"]*)" in the management interface$/
5dc361e1
SH
929 * @param string $idnumber
930 */
8aa3aa3d 931 public function i_click_to_expand_category_in_the_management_interface($idnumber) {
5dc361e1
SH
932 $categorynode = $this->get_management_category_listing_node_by_idnumber($idnumber);
933 $exception = new ExpectationException('Category "' . $idnumber . '" does not contain an expand or collapse toggle.', $this->getSession());
934 $togglenode = $this->find('css', 'a[data-action=collapse],a[data-action=expand]', $exception, $categorynode);
935 $togglenode->click();
936 }
937
938 /**
8aa3aa3d 939 * Checks that a category within the management interface is visible.
5dc361e1
SH
940 *
941 * @Given /^category in management listing should be visible "(?P<idnumber>[^"]*)"$/
942 * @param string $idnumber
943 */
944 public function category_in_management_listing_should_be_visible($idnumber) {
945 $id = $this->get_category_id($idnumber);
946 $exception = new ExpectationException('The category '.$idnumber.' is not visible.', $this->getSession());
947 $selector = sprintf('#category-listing .listitem-category[data-id="%d"][data-visible="1"]', $id);
948 $this->find('css', $selector, $exception);
949 }
950
951 /**
8aa3aa3d 952 * Checks that a category within the management interface is dimmed.
5dc361e1
SH
953 *
954 * @Given /^category in management listing should be dimmed "(?P<idnumber>[^"]*)"$/
955 * @param string $idnumber
956 */
957 public function category_in_management_listing_should_be_dimmed($idnumber) {
958 $id = $this->get_category_id($idnumber);
959 $selector = sprintf('#category-listing .listitem-category[data-id="%d"][data-visible="0"]', $id);
960 $exception = new ExpectationException('The category '.$idnumber.' is visible.', $this->getSession());
961 $this->find('css', $selector, $exception);
962 }
963
964 /**
8aa3aa3d 965 * Checks that a course within the management interface is visible.
5dc361e1
SH
966 *
967 * @Given /^course in management listing should be visible "(?P<idnumber>[^"]*)"$/
968 * @param string $idnumber
969 */
970 public function course_in_management_listing_should_be_visible($idnumber) {
971 $id = $this->get_course_id($idnumber);
972 $exception = new ExpectationException('The course '.$idnumber.' is not visible.', $this->getSession());
973 $selector = sprintf('#course-listing .listitem-course[data-id="%d"][data-visible="1"]', $id);
974 $this->find('css', $selector, $exception);
975 }
976
977 /**
8aa3aa3d 978 * Checks that a course within the management interface is dimmed.
5dc361e1
SH
979 *
980 * @Given /^course in management listing should be dimmed "(?P<idnumber>[^"]*)"$/
981 * @param string $idnumber
982 */
983 public function course_in_management_listing_should_be_dimmed($idnumber) {
984 $id = $this->get_course_id($idnumber);
985 $exception = new ExpectationException('The course '.$idnumber.' is visible.', $this->getSession());
986 $selector = sprintf('#course-listing .listitem-course[data-id="%d"][data-visible="0"]', $id);
987 $this->find('css', $selector, $exception);
988 }
989
990 /**
991 * Toggles the visibility of a course in the management UI.
992 *
993 * If it was visible it will be hidden. If it is hidden it will be made visible.
994 *
995 * @Given /^I toggle visibility of course "(?P<idnumber>[^"]*)" in management listing$/
996 * @param string $idnumber
997 */
998 public function i_toggle_visibility_of_course_in_management_listing($idnumber) {
999 $id = $this->get_course_id($idnumber);
1000 $selector = sprintf('#course-listing .listitem-course[data-id="%d"][data-visible]', $id);
1001 $node = $this->find('css', $selector);
1002 $exception = new ExpectationException('Course listing "' . $idnumber . '" does not contain a show or hide toggle.', $this->getSession());
1003 if ($node->getAttribute('data-visible') === '1') {
1004 $toggle = $this->find('css', '.action-hide', $exception, $node);
1005 } else {
1006 $toggle = $this->find('css', '.action-show', $exception, $node);
1007 }
1008 $toggle->click();
1009 }
1010
1011 /**
1012 * Toggles the visibility of a category in the management UI.
1013 *
1014 * If it was visible it will be hidden. If it is hidden it will be made visible.
1015 *
1016 * @Given /^I toggle visibility of category "(?P<idnumber>[^"]*)" in management listing$/
1017 */
1018 public function i_toggle_visibility_of_category_in_management_listing($idnumber) {
1019 $id = $this->get_category_id($idnumber);
1020 $selector = sprintf('#category-listing .listitem-category[data-id="%d"][data-visible]', $id);
1021 $node = $this->find('css', $selector);
1022 $exception = new ExpectationException('Category listing "' . $idnumber . '" does not contain a show or hide toggle.', $this->getSession());
1023 if ($node->getAttribute('data-visible') === '1') {
1024 $toggle = $this->find('css', '.action-hide', $exception, $node);
1025 } else {
1026 $toggle = $this->find('css', '.action-show', $exception, $node);
1027 }
1028 $toggle->click();
1029 }
1030
1031 /**
8aa3aa3d
SH
1032 * Moves a category displayed in the management interface up or down one place.
1033 *
1034 * @Given /^I click to move category "(?P<idnumber>[^"]*)" (?P<direction>up|down) one$/
1035 *
1036 * @param string $idnumber The category idnumber
1037 * @param string $direction The direction to move in, either up or down
5dc361e1 1038 */
8aa3aa3d
SH
1039 public function i_click_to_move_category_by_one($idnumber, $direction) {
1040 $node = $this->get_management_category_listing_node_by_idnumber($idnumber);
1041 $this->user_moves_listing_by_one('category', $node, $direction);
1042 }
1043
1044 /**
1045 * Moves a course displayed in the management interface up or down one place.
1046 *
1047 * @Given /^I click to move course "(?P<idnumber>[^"]*)" (?P<direction>up|down) one$/
1048 *
1049 * @param string $idnumber The course idnumber
1050 * @param string $direction The direction to move in, either up or down
1051 */
1052 public function i_click_to_move_course_by_one($idnumber, $direction) {
1053 $node = $this->get_management_course_listing_node_by_idnumber($idnumber);
1054 $this->user_moves_listing_by_one('course', $node, $direction);
1055 }
1056
1057 /**
1058 * Moves a course or category listing within the management interface up or down by one.
1059 *
1060 * @param string $listingtype One of course or category
1061 * @param \Behat\Mink\Element\NodeElement $listingnode
1062 * @param string $direction One of up or down.
1063 * @param bool $highlight If set to false we don't check the node has been highlighted.
1064 */
1065 protected function user_moves_listing_by_one($listingtype, $listingnode, $direction, $highlight = true) {
1066 $up = (strtolower($direction) === 'up');
5dc361e1 1067 if ($up) {
8aa3aa3d
SH
1068 $exception = new ExpectationException($listingtype.' listing does not contain a moveup button.', $this->getSession());
1069 $button = $this->find('css', 'a.action-moveup', $exception, $listingnode);
5dc361e1 1070 } else {
8aa3aa3d
SH
1071 $exception = new ExpectationException($listingtype.' listing does not contain a movedown button.', $this->getSession());
1072 $button = $this->find('css', 'a.action-movedown', $exception, $listingnode);
5dc361e1
SH
1073 }
1074 $button->click();
8aa3aa3d
SH
1075 if ($this->running_javascript() && $highlight) {
1076 $listitem = $listingnode->getParent();
5dc361e1
SH
1077 $exception = new ExpectationException('Nothing was highlighted, ajax didn\'t occur or didn\'t succeed.', $this->getSession());
1078 $this->spin(array($this, 'listing_is_highlighted'), $listitem->getTagName().'#'.$listitem->getAttribute('id'), 2, $exception, true);
1079 }
1080 }
1081
1082 /**
8aa3aa3d
SH
1083 * Used by spin to determine the callback has been highlighted.
1084 *
1085 * @param behat_course $self A self reference (default first arg from a spin callback)
1086 * @param \Behat\Mink\Element\NodeElement $selector
1087 * @return bool
5dc361e1
SH
1088 */
1089 protected function listing_is_highlighted($self, $selector) {
1090 $listitem = $this->find('css', $selector);
1091 return $listitem->hasClass('highlight');
1092 }
1093
1094 /**
8aa3aa3d 1095 * Check that one course appears before another in the course category management listings.
5dc361e1 1096 *
8aa3aa3d
SH
1097 * @Given /^I should see course listing "(?P<preceedingcourse>[^"]*)" before "(?P<followingcourse>[^"]*)"$/
1098 *
1099 * @param string $preceedingcourse The first course to find
1100 * @param string $followingcourse The second course to find (should be AFTER the first course)
1101 * @throws ExpectationException
1102 */
1103 public function i_should_see_course_listing_before($preceedingcourse, $followingcourse) {
1104 $xpath = "//div[@id='course-listing']//li[contains(concat(' ', @class, ' '), ' listitem-course ')]//a[text()='{$preceedingcourse}']/ancestor::li[@data-id]//following::a[text()='{$followingcourse}']";
1105 $msg = "{$preceedingcourse} course does not appear before {$followingcourse} course";
1106 if (!$this->getSession()->getDriver()->find($xpath)) {
1107 throw new ExpectationException($msg, $this->getSession());
1108 }
1109 }
1110
1111 /**
1112 * Check that one category appears before another in the course category management listings.
1113 *
1114 * @Given /^I should see category listing "(?P<preceedingcategory>[^"]*)" before "(?P<followingcategory>[^"]*)"$/
1115 *
1116 * @param string $preceedingcategory The first category to find
1117 * @param string $followingcategory The second category to find (should be after the first category)
1118 * @throws ExpectationException
5dc361e1 1119 */
8aa3aa3d
SH
1120 public function i_should_see_category_listing_before($preceedingcategory, $followingcategory) {
1121 $xpath = "//div[@id='category-listing']//li[contains(concat(' ', @class, ' '), ' listitem-category ')]//a[text()='{$preceedingcategory}']/ancestor::li[@data-id]//following::a[text()='{$followingcategory}']";
1122 $msg = "{$preceedingcategory} category does not appear before {$followingcategory} category";
5dc361e1
SH
1123 if (!$this->getSession()->getDriver()->find($xpath)) {
1124 throw new ExpectationException($msg, $this->getSession());
1125 }
1126 }
1127
1128 /**
8aa3aa3d 1129 * Checks that we are on the course management page that we expect to be on and that no course has been selected.
5dc361e1 1130 *
8aa3aa3d
SH
1131 * @Given /^I should see the "(?P<mode>[^"]*)" management page$/
1132 * @param string $mode The mode to expected. One of 'Courses', 'Course categories' or 'Course categories and courses'
5dc361e1
SH
1133 * @return Given[]
1134 */
8aa3aa3d 1135 public function i_should_see_the_courses_management_page($mode) {
5dc361e1
SH
1136 $return = array(
1137 new Given('I should see "Course and category management" in the "h2" "css_element"')
1138 );
1139 switch ($mode) {
1140 case "Courses":
1141 $return[] = new Given('"#category-listing" "css_element" should not exists');
1142 $return[] = new Given('"#course-listing" "css_element" should exists');
1143 break;
1144 case "Course categories":
1145 $return[] = new Given('"#category-listing" "css_element" should exists');
1146 $return[] = new Given('"#course-listing" "css_element" should not exists');
1147 break;
1148 case "Courses categories and courses":
1149 default:
1150 $return[] = new Given('"#category-listing" "css_element" should exists');
1151 $return[] = new Given('"#course-listing" "css_element" should exists');
1152 break;
1153 }
8aa3aa3d 1154 $return[] = new Given('"#course-detail" "css_element" should not exists');
5dc361e1
SH
1155 return $return;
1156 }
1157
1158 /**
8aa3aa3d
SH
1159 * Checks that we are on the course management page that we expect to be on and that a course has been selected.
1160 *
1161 * @Given /^I should see the "(?P<mode>[^"]*)" management page with a course selected$/
1162 * @param string $mode The mode to expected. One of 'Courses', 'Course categories' or 'Course categories and courses'
1163 * @return Given[]
5dc361e1 1164 */
8aa3aa3d
SH
1165 public function i_should_see_the_courses_management_page_with_a_course_selected($mode) {
1166 $return = $this->i_should_see_the_courses_management_page($mode);
1167 array_pop($return);
1168 $return[] = new Given('"#course-detail" "css_element" should exists');
1169 return $return;
1170 }
1171
1172 /**
1173 * Locates a course in the course category management interface and then triggers an action for it.
1174 *
1175 * @Given /^I click on "(?P<action>[^"]*)" action for "(?P<name>[^"]*)" in management course listing$/
1176 *
1177 * @param string $action The action to take. One of
1178 * @param string $name The name of the course as it is displayed in the management interface.
1179 */
1180 public function i_click_on_action_for_item_in_management_course_listing($action, $name) {
1181 $node = $this->get_management_course_listing_node_by_name($name);
1182 $this->user_clicks_on_management_listing_action('course', $node, $action);
1183 }
1184
1185 /**
1186 * Locates a category in the course category management interface and then triggers an action for it.
1187 *
1188 * @Given /^I click on "(?P<action>[^"]*)" action for "(?P<name>[^"]*)" in management category listing$/
1189 *
1190 * @param string $action The action to take. One of
1191 * @param string $name The name of the category as it is displayed in the management interface.
1192 */
1193 public function i_click_on_action_for_item_in_management_category_listing($action, $name) {
1194 $node = $this->get_management_category_listing_node_by_name($name);
1195 $this->user_clicks_on_management_listing_action('category', $node, $action);
1196 }
1197
1198 /**
1199 * Finds the node to use for a management listitem action and clicks it.
1200 *
1201 * @param string $listingtype Either course or category.
1202 * @param \Behat\Mink\Element\NodeElement $listingnode
1203 * @param string $action The action being taken
1204 * @throws Behat\Mink\Exception\ExpectationException
1205 */
1206 protected function user_clicks_on_management_listing_action($listingtype, $listingnode, $action) {
1207 $actionsnode = $listingnode->find('xpath', "//*[contains(concat(' ', normalize-space(@class), ' '), '{$listingtype}-item-actions')]");
5dc361e1 1208 if (!$actionsnode) {
8aa3aa3d 1209 throw new ExpectationException("Could not find the actions for $listingtype", $this->getSession());
5dc361e1
SH
1210 }
1211 $actionnode = $actionsnode->find('css', '.action-'.$action);
1212 if ($actionnode === null && $this->running_javascript()) {
1213 $actionsnode->find('css', 'a.toggle-display')->click();
1214 if ($actionnode) {
8aa3aa3d 1215 $actionnode = $listingnode->find('css', '.action-'.$action);
5dc361e1
SH
1216 }
1217 }
1218 if (!$actionnode) {
1219 throw new ExpectationException("Expected action was not available or not found ($action)", $this->getSession());
1220 }
1221 $actionnode->click();
1222 }
a1990e50 1223}