2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Backup and restore actions to help behat feature files writting.
22 * @copyright 2013 David MonllaĆ³
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
28 require_once(__DIR__
. '/../../../../../lib/behat/behat_base.php');
29 require_once(__DIR__
. '/../../../../../lib/behat/behat_field_manager.php');
31 use Behat\Gherkin\Node\TableNode
as TableNode
,
32 Behat\Mink\Exception\ElementNotFoundException
as ElementNotFoundException
,
33 Behat\Mink\Exception\ExpectationException
as ExpectationException
;
36 * Backup-related steps definitions.
40 * @copyright 2013 David MonllaĆ³
41 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43 class behat_backup
extends behat_base
{
46 * Backups the specified course using the provided options. If you are interested in restoring this backup would be useful to provide a 'Filename' option.
48 * @Given /^I backup "(?P<course_fullname_string>(?:[^"]|\\")*)" course using this options:$/
49 * @param string $backupcourse
50 * @param TableNode $options Backup options or false if no options provided
52 public function i_backup_course_using_this_options($backupcourse, $options = false) {
54 // We can not use other steps here as we don't know where the provided data
55 // table elements are used, and we need to catch exceptions contantly.
58 $this->getSession()->visit($this->locate_path('/'));
60 // Click the course link.
61 $this->find_link($backupcourse)->click();
63 // Click the backup link.
64 $this->find_link('Backup')->click();
67 $this->fill_backup_restore_form($options);
68 $this->find_button('Next')->press();
71 $this->fill_backup_restore_form($options);
72 $this->find_button('Next')->press();
74 // Confirmation and review, backup filename can also be specified.
75 $this->fill_backup_restore_form($options);
76 $this->find_button('Perform backup')->press();
78 // Waiting for it to finish.
81 // Last backup continue button.
82 $this->find_button('Continue')->press();
86 * Imports the specified origin course into the other course using the provided options.
88 * Keeping it separatelly from backup & restore, it the number of
89 * steps and duplicate code becomes bigger a common method should
92 * @Given /^I import "(?P<from_course_fullname_string>(?:[^"]|\\")*)" course into "(?P<to_course_fullname_string>(?:[^"]|\\")*)" course using this options:$/
93 * @param string $fromcourse
94 * @param string $tocourse
95 * @param TableNode $options
97 public function i_import_course_into_course($fromcourse, $tocourse, $options = false) {
99 // We can not use other steps here as we don't know where the provided data
100 // table elements are used, and we need to catch exceptions contantly.
103 $this->getSession()->visit($this->locate_path('/'));
105 // Click the course link.
106 $this->find_link($tocourse)->click();
108 // Click the backup link.
109 $this->find_link('Import')->click();
111 // Select the course.
112 $exception = new ExpectationException('"' . $fromcourse . '" course not found in the list of courses to import from', $this->getSession());
114 $fromcourse = str_replace("'", "\'", $fromcourse);
115 $xpath = "//div[contains(concat(' ', @class, ' '), ' ics-results ')]" .
116 "/descendant::tr[contains(., '" . $fromcourse . "')]" .
117 "/descendant::input[@type='radio']";
118 $radionode = $this->find('xpath', $xpath, $exception);
122 $this->find_button('Continue')->press();
125 $this->fill_backup_restore_form($options);
126 $this->find_button('Next')->press();
129 $this->fill_backup_restore_form($options);
130 $this->find_button('Next')->press();
133 $this->find_button('Perform import')->press();
136 // Continue and redirect to 'to' course.
137 $this->find_button('Continue')->press();
141 * Restores the backup into the specified course and the provided options. You should be in the 'Restore' page where the backup is.
143 * @Given /^I restore "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into "(?P<existing_course_fullname_string>(?:[^"]|\\")*)" course using this options:$/
144 * @param string $backupfilename
145 * @param string $existingcourse
146 * @param TableNode $options Restore forms options or false if no options provided
148 public function i_restore_backup_into_course_using_this_options($backupfilename, $existingcourse, $options = false) {
151 $this->select_backup($backupfilename);
153 // Selecting the specified course (we can not call behat_forms::select_radio here as is in another behat subcontext).
154 $existingcourse = str_replace("'", "\'", $existingcourse);
155 $radionode = $this->find('xpath', "//div[contains(@class, 'bcs-existing-course')]" .
156 "/descendant::div[@class='restore-course-search']" .
157 "/descendant::tr[contains(., '" . $existingcourse . "')]" .
158 "/descendant::input[@type='radio']");
162 // Pressing the continue button of the restore into an existing course section.
163 $continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-existing-course')]/descendant::input[@type='submit'][@value='Continue']");
164 $continuenode->click();
167 // Common restore process using provided key/value options.
168 $this->process_restore($options);
172 * Restores the specified backup into a new course using the provided options. You should be in the 'Restore' page where the backup is.
174 * @Given /^I restore "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into a new course using this options:$/
175 * @param string $backupfilename
176 * @param TableNode $options Restore forms options or false if no options provided
178 public function i_restore_backup_into_a_new_course_using_this_options($backupfilename, $options = false) {
181 $this->select_backup($backupfilename);
183 // The first category in the list.
184 $radionode = $this->find('xpath', "//div[contains(@class, 'bcs-new-course')]" .
185 "/descendant::div[@class='restore-course-search']" .
186 "/descendant::input[@type='radio']");
190 // Pressing the continue button of the restore into an existing course section.
191 $continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-new-course')]/descendant::input[@type='submit'][@value='Continue']");
192 $continuenode->click();
195 // Common restore process using provided key/value options.
196 $this->process_restore($options);
200 * Merges the backup into the current course using the provided restore options. You should be in the 'Restore' page where the backup is.
202 * @Given /^I merge "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into the current course using this options:$/
203 * @param string $backupfilename
204 * @param TableNode $options Restore forms options or false if no options provided
206 public function i_merge_backup_into_the_current_course($backupfilename, $options = false) {
209 $this->select_backup($backupfilename);
211 // Merge without deleting radio option.
212 $radionode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
213 "/descendant::input[@type='radio'][@name='target'][@value='1']");
217 // Pressing the continue button of the restore merging section.
218 $continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
219 "/descendant::input[@type='submit'][@value='Continue']");
220 $continuenode->click();
223 // Common restore process using provided key/value options.
224 $this->process_restore($options);
228 * Merges the backup into the current course after deleting this contents, using the provided restore options. You should be in the 'Restore' page where the backup is.
230 * @Given /^I merge "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into the current course after deleting it's contents using this options:$/
231 * @param string $backupfilename
232 * @param TableNode $options Restore forms options or false if no options provided
234 public function i_merge_backup_into_current_course_deleting_its_contents($backupfilename, $options = false) {
237 $this->select_backup($backupfilename);
239 // Delete contents radio option.
240 $radionode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
241 "/descendant::input[@type='radio'][@name='target'][@value='0']");
245 // Pressing the continue button of the restore merging section.
246 $continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
247 "/descendant::input[@type='submit'][@value='Continue']");
248 $continuenode->click();
251 // Common restore process using provided key/value options.
252 $this->process_restore($options);
256 * Selects the backup to restore.
258 * @throws ExpectationException
259 * @param string $backupfilename
262 protected function select_backup($backupfilename) {
264 // Using xpath as there are other restore links before this one.
265 $exception = new ExpectationException('The "' . $backupfilename . '" backup file can not be found in this page', $this->getSession());
266 $xpath = "//tr[contains(., '" . $backupfilename . "')]/descendant::a[contains(., 'Restore')]";
267 $restorelink = $this->find('xpath', $xpath, $exception);
268 $restorelink->click();
270 // Confirm the backup contents.
271 $restore = $this->find_button('Continue')->press();
275 * Executes the common steps of all restore processes.
277 * @param TableNode $options The backup and restore options or false if no options provided
280 protected function process_restore($options) {
282 // We can not use other steps here as we don't know where the provided data
283 // table elements are used, and we need to catch exceptions contantly.
286 $this->fill_backup_restore_form($options);
287 $this->find_button('Next')->press();
290 $this->fill_backup_restore_form($options);
291 $this->find_button('Next')->press();
293 // Review, no options here.
294 $this->find_button('Perform restore')->press();
297 // Last restore continue button, redirected to restore course after this.
298 $this->find_button('Continue')->press();
302 * Tries to fill the current page form elements with the provided options.
304 * This step is slow as it spins over each provided option, we are
305 * not expected to have lots of provided options, anyways, is better
306 * to be conservative and wait for the elements to appear rather than
307 * to have false failures.
309 * @param TableNode $options The backup and restore options or false if no options provided
312 protected function fill_backup_restore_form($options) {
314 // Nothing to fill if no options are provided.
319 // If we find any of the provided options in the current form we should set the value.
320 $datahash = $options->getRowsHash();
321 foreach ($datahash as $locator => $value) {
324 $fieldnode = $this->find_field($locator);
325 $field = behat_field_manager
::get_field($fieldnode, $locator, $this->getSession());
326 $field->set_value($value);
328 } catch (ElementNotFoundException
$e) {
329 // Next provided option then, this one should be part of another page's fields.
335 * Waits until the DOM is ready.
337 * @param int To override the default timeout
340 protected function wait($timeout = false) {
343 $timeout = self
::TIMEOUT
;
345 $this->getSession()->wait($timeout, '(document.readyState === "complete")');