weekly release 2.6dev
[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
67 */
68 public function i_create_a_course_with(TableNode $table) {
69 return array(
70 new Given('I go to the courses management page'),
dedb9738 71 new Given('I press "' . get_string('addnewcourse') . '"'),
df1ff55d 72 new Given('I fill the moodle form with:', $table),
dedb9738 73 new Given('I press "' . get_string('savechanges') . '"')
df1ff55d
DM
74 );
75 }
76
77 /**
78 * Goes to the system courses/categories management page.
79 *
80 * @Given /^I go to the courses management page$/
81 */
82 public function i_go_to_the_courses_management_page() {
83
84 return array(
85 new Given('I am on homepage'),
dedb9738
DM
86 new Given('I expand "' . get_string('administrationsite') . '" node'),
87 new Given('I expand "' . get_string('courses', 'admin') . '" node'),
88 new Given('I follow "' . get_string('coursemgmt', 'admin') . '"'),
df1ff55d
DM
89 );
90 }
91
a1990e50
DM
92 /**
93 * Adds the selected activity/resource filling the form data with the specified field/value pairs.
94 *
44d5af38 95 * @When /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)" and I fill the form with:$/
a1990e50 96 * @param string $activity The activity name
0e575f01 97 * @param int $section The section number
a1990e50
DM
98 * @param TableNode $data The activity field/value data
99 */
100 public function i_add_to_section_and_i_fill_the_form_with($activity, $section, TableNode $data) {
101
a1990e50 102 return array(
38976081 103 new Given('I add a "' . $this->escape($activity) . '" to section "' . $this->escape($section) . '"'),
a1990e50 104 new Given('I fill the moodle form with:', $data),
dedb9738 105 new Given('I press "' . get_string('savechangesandreturntocourse') . '"')
a1990e50
DM
106 );
107 }
108
109 /**
110 * Opens the activity chooser and opens the activity/resource form page.
111 *
44d5af38 112 * @Given /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)"$/
1f9ffbdb 113 * @throws ElementNotFoundException Thrown by behat_base::find
a1990e50 114 * @param string $activity
0e575f01 115 * @param int $section
a1990e50
DM
116 */
117 public function i_add_to_section($activity, $section) {
118
38976081
DM
119 $sectionxpath = "//li[@id='section-" . $section . "']";
120
121 $activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral(ucfirst($activity));
1c00d6f6
DM
122
123 if ($this->running_javascript()) {
124
125 // Clicks add activity or resource section link.
126 $sectionxpath = $sectionxpath . "/descendant::div[@class='section-modchooser']/span/a";
127 $sectionnode = $this->find('xpath', $sectionxpath);
128 $sectionnode->click();
129
130 // Clicks the selected activity if it exists.
00ea74cb 131 $activityxpath = "//div[@id='chooseform']/descendant::label" .
38976081
DM
132 "/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
133 "[contains(., $activityliteral)]" .
00ea74cb 134 "/parent::label/child::input";
1c00d6f6
DM
135 $activitynode = $this->find('xpath', $activityxpath);
136 $activitynode->doubleClick();
137
138 } else {
139 // Without Javascript.
140
141 // Selecting the option from the select box which contains the option.
38976081
DM
142 $selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
143 "/descendant::select[contains(., $activityliteral)]";
1c00d6f6
DM
144 $selectnode = $this->find('xpath', $selectxpath);
145 $selectnode->selectOption($activity);
146
147 // Go button.
148 $gobuttonxpath = $selectxpath . "/ancestor::form/descendant::input[@type='submit']";
149 $gobutton = $this->find('xpath', $gobuttonxpath);
150 $gobutton->click();
151 }
152
a1990e50
DM
153 }
154
18c84063
DM
155 /**
156 * Turns course section highlighting on.
157 *
158 * @Given /^I turn section "(?P<section_number>\d+)" highlighting on$/
159 * @param int $sectionnumber The section number
160 */
161 public function i_turn_section_highlighting_on($sectionnumber) {
162
163 // Ensures the section exists.
164 $xpath = $this->section_exists($sectionnumber);
165
166 return array(
38976081 167 new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
18c84063
DM
168 new Given('I wait "2" seconds')
169 );
170 }
171
172 /**
173 * Turns course section highlighting off.
174 *
175 * @Given /^I turn section "(?P<section_number>\d+)" highlighting off$/
176 * @param int $sectionnumber The section number
177 */
178 public function i_turn_section_highlighting_off($sectionnumber) {
179
180 // Ensures the section exists.
181 $xpath = $this->section_exists($sectionnumber);
182
183 return array(
38976081 184 new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
18c84063
DM
185 new Given('I wait "2" seconds')
186 );
187 }
188
189 /**
b918f9f7
DM
190 * Shows the specified hidden section. You need to be in the course page and on editing mode.
191 *
192 * @Given /^I show section "(?P<section_number>\d+)"$/
193 * @param int $sectionnumber
194 */
195 public function i_show_section($sectionnumber) {
0e575f01
DM
196 $showlink = $this->show_section_icon_exists($sectionnumber);
197 $showlink->click();
b918f9f7
DM
198
199 // It requires time.
0e575f01
DM
200 if ($this->running_javascript()) {
201 $this->getSession()->wait(5000, false);
202 }
b918f9f7
DM
203 }
204
205 /**
206 * Hides the specified visible section. You need to be in the course page and on editing mode.
207 *
208 * @Given /^I hide section "(?P<section_number>\d+)"$/
209 * @param int $sectionnumber
210 */
211 public function i_hide_section($sectionnumber) {
0e575f01
DM
212 $hidelink = $this->hide_section_icon_exists($sectionnumber);
213 $hidelink->click();
b918f9f7
DM
214
215 // It requires time.
0e575f01
DM
216 if ($this->running_javascript()) {
217 $this->getSession()->wait(5000, false);
218 }
b918f9f7
DM
219 }
220
221 /**
222 * Checks if the specified course section hightlighting is turned on. You need to be in the course page on editing mode.
18c84063 223 *
18c84063 224 * @Then /^section "(?P<section_number>\d+)" should be highlighted$/
b918f9f7 225 * @throws ExpectationException
18c84063
DM
226 * @param int $sectionnumber The section number
227 */
228 public function section_should_be_highlighted($sectionnumber) {
229
230 // Ensures the section exists.
231 $xpath = $this->section_exists($sectionnumber);
232
233 // The important checking, we can not check the img.
234 $xpath = $xpath . "/descendant::img[@alt='" . get_string('markedthistopic') . "'][contains(@src, 'marked')]";
235 $exception = new ExpectationException('The "' . $sectionnumber . '" section is not highlighted', $this->getSession());
236 $this->find('xpath', $xpath, $exception);
237 }
238
239 /**
b918f9f7 240 * Checks if the specified course section highlighting is turned off. You need to be in the course page on editing mode.
18c84063
DM
241 *
242 * @Then /^section "(?P<section_number>\d+)" should not be highlighted$/
b918f9f7 243 * @throws ExpectationException
18c84063
DM
244 * @param int $sectionnumber The section number
245 */
246 public function section_should_not_be_highlighted($sectionnumber) {
247
248 // We only catch ExpectationException, ElementNotFoundException should be thrown if the specified section does not exist.
249 try {
250 $this->section_should_be_highlighted($sectionnumber);
251 } catch (ExpectationException $e) {
252 // ExpectedException means that it is not highlighted.
253 return;
254 }
255
256 throw new ExpectationException('The "' . $sectionnumber . '" section is highlighted', $this->getSession());
257 }
258
b918f9f7
DM
259 /**
260 * 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.
261 *
262 * @Then /^section "(?P<section_number>\d+)" should be hidden$/
263 * @throws ExpectationException
264 * @throws ElementNotFoundException Thrown by behat_base::find
265 * @param int $sectionnumber
266 */
267 public function section_should_be_hidden($sectionnumber) {
268
269 $sectionxpath = $this->section_exists($sectionnumber);
270
271 // Section should be hidden.
272 $exception = new ExpectationException('The section is not hidden', $this->getSession());
38976081 273 $this->find('xpath', $sectionxpath . "[contains(concat(' ', normalize-space(@class), ' '), ' hidden ')]", $exception);
b918f9f7
DM
274
275 // The checking are different depending on user permissions.
276 if ($this->is_course_editor()) {
277
278 // The section must be hidden.
279 $this->show_section_icon_exists($sectionnumber);
280
281 // If there are activities they should be hidden and the visibility icon should not be available.
282 if ($activities = $this->get_section_activities($sectionxpath)) {
283
284 $dimmedexception = new ExpectationException('There are activities that are not dimmed', $this->getSession());
285 $visibilityexception = new ExpectationException('There are activities which visibility icons are clickable', $this->getSession());
286 foreach ($activities as $activity) {
287
288 // Dimmed.
38976081
DM
289 $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' activityinstance ')]" .
290 "/a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity);
b918f9f7 291
0e575f01
DM
292 // Non-JS browsers can not click on img elements.
293 if ($this->running_javascript()) {
294 // To check that the visibility is not clickable we check the funcionality rather than the applied style.
295 $visibilityiconnode = $this->find('css', 'a.editing_show img', false, $activity);
296 $visibilityiconnode->click();
297 }
b918f9f7
DM
298
299 // We ensure that we still see the show icon.
300 $visibilityiconnode = $this->find('css', 'a.editing_show img', $visibilityexception, $activity);
301 }
302 }
303
304 } else {
305 // There shouldn't be activities.
306 if ($this->get_section_activities($sectionxpath)) {
307 throw new ExpectationException('There are activities in the section and they should be hidden', $this->getSession());
308 }
309 }
310 }
311
312 /**
313 * 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.
314 *
315 * @Then /^section "(?P<section_number>\d+)" should be visible$/
316 * @throws ExpectationException
317 * @param int $sectionnumber
318 */
319 public function section_should_be_visible($sectionnumber) {
320
321 $sectionxpath = $this->section_exists($sectionnumber);
322
323 // Section should not be hidden.
38976081
DM
324 $xpath = $sectionxpath . "[not(contains(concat(' ', normalize-space(@class), ' '), ' hidden '))]";
325 if (!$this->getSession()->getPage()->find('xpath', $xpath)) {
b918f9f7
DM
326 throw new ExpectationException('The section is hidden', $this->getSession());
327 }
328
329 // Hide section button should be visible.
330 if ($this->is_course_editor()) {
331 $this->hide_section_icon_exists($sectionnumber);
332 }
333 }
334
0e575f01
DM
335 /**
336 * Moves up the specified section, this step only works with Javascript disabled. Editing mode should be on.
337 *
338 * @Given /^I move up section "(?P<section_number>\d+)"$/
339 * @throws DriverException Step not available when Javascript is enabled
340 * @param int $sectionnumber
341 */
342 public function i_move_up_section($sectionnumber) {
343
344 if ($this->running_javascript()) {
345 throw new DriverException('Move a section up step is not available with Javascript enabled');
346 }
347
348 // Ensures the section exists.
349 $sectionxpath = $this->section_exists($sectionnumber);
350
351 // Follows the link
352 $moveuplink = $this->get_node_in_container('link', get_string('moveup'), 'xpath_element', $sectionxpath);
353 $moveuplink->click();
354 }
355
356 /**
357 * Moves down the specified section, this step only works with Javascript disabled. Editing mode should be on.
358 *
359 * @Given /^I move down section "(?P<section_number>\d+)"$/
360 * @throws DriverException Step not available when Javascript is enabled
361 * @param int $sectionnumber
362 */
363 public function i_move_down_section($sectionnumber) {
364
365 if ($this->running_javascript()) {
366 throw new DriverException('Move a section down step is not available with Javascript enabled');
367 }
368
369 // Ensures the section exists.
370 $sectionxpath = $this->section_exists($sectionnumber);
371
372 // Follows the link
373 $movedownlink = $this->get_node_in_container('link', get_string('movedown'), 'xpath_element', $sectionxpath);
374 $movedownlink->click();
375 }
376
bf648567
DM
377 /**
378 * 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.
379 *
380 * @Then /^"(?P<activity_or_resource_string>(?:[^"]|\\")*)" activity should be visible$/
381 * @param string $activityname
382 */
383 public function activity_should_be_visible($activityname) {
384
385 // The activity must exists and be visible.
386 $activitynode = $this->get_activity_node($activityname);
387
388 if ($this->is_course_editor()) {
389
390 // The activity should not be dimmed.
391 try {
392 $this->find('css', 'a.dimmed', false, $activitynode);
393 throw new ExpectationException('"' . $activityname . '" is hidden', $this->getSession());
394 } catch (ElementNotFoundException $e) {
395 // All ok.
396 }
397
398 // The 'Hide' button should be available.
399 $nohideexception = new ExpectationException('"' . $activityname . '" don\'t have a "' . get_string('hide') . '" icon', $this->getSession());
400 $this->find('named', array('link', get_string('hide')), $nohideexception, $activitynode);
401 }
402 }
403
404 /**
405 * 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.
406 *
407 * @Then /^"(?P<activity_or_resource_string>(?:[^"]|\\")*)" activity should be hidden$/
408 * @param string $activityname
409 */
410 public function activity_should_be_hidden($activityname) {
411
412 if ($this->is_course_editor()) {
413
414 // The activity should exists.
415 $activitynode = $this->get_activity_node($activityname);
416
417 // Should be hidden.
418 $exception = new ExpectationException('"' . $activityname . '" is not dimmed', $this->getSession());
419 $this->find('css', 'a.dimmed', $exception, $activitynode);
420
421 // Also 'Show' icon.
422 $noshowexception = new ExpectationException('"' . $activityname . '" don\'t have a "' . get_string('show') . '" icon', $this->getSession());
423 $this->find('named', array('link', get_string('show')), $noshowexception, $activitynode);
424
425 } else {
426
427 // It should not exists at all.
428 try {
429 $this->find_link($activityname);
430 throw new ExpectationException('The "' . $activityname . '" should not appear');
431 } catch (ElementNotFoundException $e) {
432 // This is good, the activity should not be there.
433 }
434 }
435
436 }
437
0e575f01 438 /**
7daab401 439 * 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
440 *
441 * @Given /^I move "(?P<activity_name_string>(?:[^"]|\\")*)" activity to section "(?P<section_number>\d+)"$/
442 * @param string $activityname The activity name
443 * @param int $sectionnumber The number of section
444 */
445 public function i_move_activity_to_section($activityname, $sectionnumber) {
446
447 // Ensure the destination is valid.
448 $sectionxpath = $this->section_exists($sectionnumber);
449
450 $activitynode = $this->get_activity_element('.editing_move img', 'css_element', $activityname);
451
452 // JS enabled.
453 if ($this->running_javascript()) {
454
38976081 455 $destinationxpath = $sectionxpath . "/descendant::ul[contains(concat(' ', normalize-space(@class), ' '), ' yui3-dd-drop ')]";
0e575f01
DM
456
457 return array(
38976081
DM
458 new Given('I drag "' . $this->escape($activitynode->getXpath()) . '" "xpath_element" ' .
459 'and I drop it in "' . $this->escape($destinationxpath) . '" "xpath_element"'),
0e575f01
DM
460 );
461
462 } else {
463 // Following links with no-JS.
464
465 // Moving to the fist spot of the section (before all other section's activities).
466 return array(
38976081
DM
467 new Given('I click on "a.editing_move" "css_element" in the "' . $this->escape($activityname) . '" activity'),
468 new Given('I click on "li.movehere a" "css_element" in the "' . $this->escape($sectionxpath) . '" "xpath_element"'),
0e575f01
DM
469 );
470 }
471 }
472
473 /**
474 * Edits the activity name through the edit activity; this step only works with Javascript enabled. Editing mode should be on.
475 *
476 * @Given /^I change "(?P<activity_name_string>(?:[^"]|\\")*)" activity name to "(?P<new_name_string>(?:[^"]|\\")*)"$/
477 * @throws DriverException Step not available when Javascript is disabled
478 * @param string $activityname
479 * @param string $newactivityname
480 */
481 public function i_change_activity_name_to($activityname, $newactivityname) {
482
483 if (!$this->running_javascript()) {
484 throw new DriverException('Change activity name step is not available with Javascript disabled');
485 }
486
487 // Adding chr(10) to save changes.
e5de4933 488 $activity = $this->escape($activityname);
0e575f01 489 return array(
e5de4933
SH
490 new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity'),
491 new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $activity .'" activity'),
38976081 492 new Given('I fill in "title" with "' . $this->escape($newactivityname) . chr(10) . '"'),
0e575f01
DM
493 new Given('I wait "2" seconds')
494 );
495 }
496
497 /**
498 * Indents to the right the activity or resource specified by it's name. Editing mode should be on.
499 *
500 * @Given /^I indent right "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
501 * @param string $activityname
502 */
503 public function i_indent_right_activity($activityname) {
504
e5de4933
SH
505 $steps = array();
506 $activity = $this->escape($activityname);
507 if ($this->running_javascript()) {
508 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
509 }
510 $steps[] = new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $activity . '" activity');
0e575f01
DM
511
512 if ($this->running_javascript()) {
513 $steps[] = new Given('I wait "2" seconds');
514 }
515
516 return $steps;
517 }
518
519 /**
520 * Indents to the left the activity or resource specified by it's name. Editing mode should be on.
521 *
522 * @Given /^I indent left "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
523 * @param string $activityname
524 */
525 public function i_indent_left_activity($activityname) {
526
e5de4933
SH
527 $steps = array();
528 $activity = $this->escape($activityname);
529 if ($this->running_javascript()) {
530 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
531 }
532 $steps[] = new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $activity . '" activity');
0e575f01
DM
533
534 if ($this->running_javascript()) {
535 $steps[] = new Given('I wait "2" seconds');
536 }
537
538 return $steps;
539
540 }
541
542 /**
7daab401 543 * 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
544 *
545 * @Given /^I delete "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
546 * @param string $activityname
547 */
548 public function i_delete_activity($activityname) {
549
550 $deletestring = get_string('delete');
551
552 // JS enabled.
553 // Not using chain steps here because the exceptions catcher have problems detecting
554 // JS modal windows and avoiding interacting them at the same time.
555 if ($this->running_javascript()) {
556
557 $element = $this->get_activity_element($deletestring, 'link', $activityname);
558 $element->click();
559
560 $this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
561
562 $this->getSession()->wait(2 * 1000, false);
563
564 } else {
565
566 // With JS disabled.
567 $steps = array(
38976081 568 new Given('I click on "' . $this->escape($deletestring) . '" "link" in the "' . $this->escape($activityname) . '" activity'),
0e575f01
DM
569 new Given('I press "' . get_string('yes') . '"')
570 );
571
572 return $steps;
573 }
574 }
575
576 /**
577 * Duplicates the activity or resource specified by it's name. You should be in the course page with editing mode on.
578 *
579 * @Given /^I duplicate "(?P<activity_name_string>(?:[^"]|\\")*)" activity$/
580 * @param string $activityname
581 */
582 public function i_duplicate_activity($activityname) {
e5de4933
SH
583 $steps = array();
584 $activity = $this->escape($activityname);
585 if ($this->running_javascript()) {
586 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
587 }
588 $steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
589 $steps[] = new Given('I press "' . get_string('continue') .'"');
590 $steps[] = new Given('I press "' . get_string('duplicatecontcourse') .'"');
591 return $steps;
0e575f01
DM
592 }
593
594 /**
595 * 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.
596 *
597 * @Given /^I duplicate "(?P<activity_name_string>(?:[^"]|\\")*)" activity editing the new copy with:$/
598 * @param string $activityname
599 * @param TableNode $data
600 */
601 public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) {
e5de4933
SH
602 $steps = array();
603 $activity = $this->escape($activityname);
604 if ($this->running_javascript()) {
605 $steps[] = new Given('I click on "' . get_string('actions', 'moodle') . '" "link" in the "' . $activity . '" activity');
606 }
607 $steps[] = new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activity . '" activity');
608 $steps[] = new Given('I press "' . get_string('continue') .'"');
609 $steps[] = new Given('I press "' . get_string('duplicatecontedit') . '"');
610 $steps[] = new Given('I fill the moodle form with:', $data);
611 $steps[] = new Given('I press "' . get_string('savechangesandreturntocourse') . '"');
612 return $steps;
0e575f01
DM
613 }
614
615 /**
616 * Clicks on the specified element of the activity. You should be in the course page with editing mode turned on.
617 *
618 * @Given /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<activity_name_string>[^"]*)" activity$/
619 * @param string $element
620 * @param string $selectortype
621 * @param string $activityname
622 */
623 public function i_click_on_in_the_activity($element, $selectortype, $activityname) {
624 $element = $this->get_activity_element($element, $selectortype, $activityname);
625 $element->click();
626 }
627
628 /**
629 * Clicks on the specified element inside the activity container.
630 *
631 * @throws ElementNotFoundException
632 * @param string $element
633 * @param string $selectortype
634 * @param string $activityname
635 * @return NodeElement
636 */
637 protected function get_activity_element($element, $selectortype, $activityname) {
638 $activitynode = $this->get_activity_node($activityname);
639
640 // Transforming to Behat selector/locator.
641 list($selector, $locator) = $this->transform_selector($selectortype, $element);
642 $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . $selectortype . '" in "' . $activityname . '" ');
643
644 return $this->find($selector, $locator, $exception, $activitynode);
645 }
646
18c84063
DM
647 /**
648 * Checks if the course section exists.
649 *
650 * @throws ElementNotFoundException Thrown by behat_base::find
651 * @param int $sectionnumber
b918f9f7 652 * @return string The xpath of the section.
18c84063
DM
653 */
654 protected function section_exists($sectionnumber) {
655
656 // Just to give more info in case it does not exist.
657 $xpath = "//li[@id='section-" . $sectionnumber . "']";
658 $exception = new ElementNotFoundException($this->getSession(), "Section $sectionnumber ");
659 $this->find('xpath', $xpath, $exception);
660
661 return $xpath;
662 }
b918f9f7
DM
663
664 /**
665 * Returns the show section icon or throws an exception.
666 *
667 * @throws ElementNotFoundException Thrown by behat_base::find
668 * @param int $sectionnumber
669 * @return NodeElement
670 */
671 protected function show_section_icon_exists($sectionnumber) {
672
673 // Gets the section xpath and ensure it exists.
674 $xpath = $this->section_exists($sectionnumber);
675
676 // We need to know the course format as the text strings depends on them.
677 $courseformat = $this->get_course_format();
678
679 // Checking the show button alt text and show icon.
38976081
DM
680 $showtext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('showfromothers', $courseformat));
681 $linkxpath = $xpath . "/descendant::a[@title=$showtext]";
682 $imgxpath = $linkxpath . "/descendant::img[@alt=$showtext][contains(@src, 'show')]";
b918f9f7
DM
683
684 $exception = new ElementNotFoundException($this->getSession(), 'Show section icon ');
0e575f01
DM
685 $this->find('xpath', $imgxpath, $exception);
686
687 // Returing the link so both Non-JS and JS browsers can interact with it.
688 return $this->find('xpath', $linkxpath, $exception);
b918f9f7
DM
689 }
690
691 /**
692 * Returns the hide section icon link if it exists or throws exception.
693 *
694 * @throws ElementNotFoundException Thrown by behat_base::find
695 * @param int $sectionnumber
696 * @return NodeElement
697 */
698 protected function hide_section_icon_exists($sectionnumber) {
699
700 // Gets the section xpath and ensure it exists.
701 $xpath = $this->section_exists($sectionnumber);
702
703 // We need to know the course format as the text strings depends on them.
704 $courseformat = $this->get_course_format();
705
706 // Checking the hide button alt text and hide icon.
38976081
DM
707 $hidetext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('hidefromothers', $courseformat));
708 $linkxpath = $xpath . "/descendant::a[@title=$hidetext]";
709 $imgxpath = $linkxpath . "/descendant::img[@alt=$hidetext][contains(@src, 'hide')]";
b918f9f7
DM
710
711 $exception = new ElementNotFoundException($this->getSession(), 'Hide section icon ');
0e575f01
DM
712 $this->find('xpath', $imgxpath, $exception);
713
714 // Returing the link so both Non-JS and JS browsers can interact with it.
715 return $this->find('xpath', $linkxpath, $exception);
b918f9f7
DM
716 }
717
718 /**
719 * Gets the current course format.
720 *
721 * @throws ExpectationException If we are not in the course view page.
722 * @return string The course format in a frankenstyled name.
723 */
724 protected function get_course_format() {
725
726 $exception = new ExpectationException('You are not in a course page', $this->getSession());
727
728 // The moodle body's id attribute contains the course format.
729 $node = $this->getSession()->getPage()->find('css', 'body');
730 if (!$node) {
731 throw $exception;
732 }
733
734 if (!$bodyid = $node->getAttribute('id')) {
735 throw $exception;
736 }
737
738 if (strstr($bodyid, 'page-course-view-') === false) {
739 throw $exception;
740 }
741
742 return 'format_' . str_replace('page-course-view-', '', $bodyid);
743 }
744
745 /**
746 * Gets the section's activites DOM nodes.
747 *
748 * @param string $sectionxpath
749 * @return array NodeElement instances
750 */
751 protected function get_section_activities($sectionxpath) {
752
38976081 753 $xpath = $sectionxpath . "/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]";
b918f9f7
DM
754
755 // We spin here, as activities usually require a lot of time to load.
756 try {
757 $activities = $this->find_all('xpath', $xpath);
758 } catch (ElementNotFoundException $e) {
759 return false;
760 }
761
762 return $activities;
763 }
764
bf648567
DM
765 /**
766 * Returns the DOM node of the activity from <li>.
767 *
768 * @throws ElementNotFoundException Thrown by behat_base::find
769 * @param string $activityname The activity name
770 * @return NodeElement
771 */
772 protected function get_activity_node($activityname) {
773
38976081
DM
774 $activityname = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname);
775 $xpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityname)]";
bf648567
DM
776
777 return $this->find('xpath', $xpath);
778 }
779
b918f9f7
DM
780 /**
781 * Returns whether the user can edit the course contents or not.
782 *
783 * @return bool
784 */
785 protected function is_course_editor() {
786
787 // We don't need to behat_base::spin() here as all is already loaded.
dedb9738
DM
788 if (!$this->getSession()->getPage()->findButton(get_string('turneditingoff')) &&
789 !$this->getSession()->getPage()->findButton(get_string('turneditingon'))) {
b918f9f7
DM
790 return false;
791 }
792
793 return true;
794 }
795
a1990e50 796}