source: moodle/trunk/fuentes/backup/util/ui/tests/behat/behat_backup.php @ 1331

Last change on this file since 1331 was 1331, checked in by jrpelegrina, 3 years ago

Updated to moodle 3.0.3

File size: 18.5 KB
Line 
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 * Backup and restore actions to help behat feature files writting.
19 *
20 * @package    core_backup
21 * @category   test
22 * @copyright  2013 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');
29require_once(__DIR__ . '/../../../../../lib/behat/behat_field_manager.php');
30require_once(__DIR__ . '/../../../../../lib/tests/behat/behat_navigation.php');
31
32use Behat\Gherkin\Node\TableNode as TableNode,
33    Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
34    Behat\Mink\Exception\ExpectationException as ExpectationException;
35
36/**
37 * Backup-related steps definitions.
38 *
39 * @package    core_backup
40 * @category   test
41 * @copyright  2013 David Monllaó
42 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43 */
44class behat_backup extends behat_base {
45
46    /**
47     * Follow a link like 'Backup' or 'Import', where the link name comes from
48     * a language string, in the settings nav block of a course.
49     * @param string $langstring the lang string to look for. E.g. 'backup' or 'import'.
50     * @param string $component (optional) second argument to {@link get_string}.
51     */
52    protected function navigate_to_course_settings_link($langstring, $component = '') {
53        $behatnavigation = new behat_navigation();
54        $behatnavigation->setMink($this->getMink());
55        $behatnavigation->i_navigate_to_node_in(get_string($langstring, $component),
56                get_string('courseadministration'));
57    }
58
59    /**
60     * Backups the specified course using the provided options. If you are interested in restoring this backup would be
61     * useful to provide a 'Filename' option.
62     *
63     * @Given /^I backup "(?P<course_fullname_string>(?:[^"]|\\")*)" course using this options:$/
64     * @param string $backupcourse
65     * @param TableNode $options Backup options or false if no options provided
66     */
67    public function i_backup_course_using_this_options($backupcourse, $options = false) {
68        // We can not use other steps here as we don't know where the provided data
69        // table elements are used, and we need to catch exceptions contantly.
70
71        // Go to homepage.
72        $this->getSession()->visit($this->locate_path('/?redirect=0'));
73
74        // Click the course link.
75        $this->find_link($backupcourse)->click();
76
77        // Click the backup link.
78        $this->navigate_to_course_settings_link('backup');
79        $this->wait();
80
81        // Initial settings.
82        $this->fill_backup_restore_form($this->get_step_options($options, "Initial"));
83        $this->find_button(get_string('backupstage1action', 'backup'))->press();
84        $this->wait();
85
86        // Schema settings.
87        $this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
88        $this->find_button(get_string('backupstage2action', 'backup'))->press();
89        $this->wait();
90
91        // Confirmation and review, backup filename can also be specified.
92        $this->fill_backup_restore_form($this->get_step_options($options, "Confirmation"));
93        $this->find_button(get_string('backupstage4action', 'backup'))->press();
94
95        // Waiting for it to finish.
96        $this->wait(self::EXTENDED_TIMEOUT);
97
98        // Last backup continue button.
99        $this->find_button(get_string('backupstage16action', 'backup'))->press();
100    }
101
102    /**
103     * Performs a quick (one click) backup of a course.
104     *
105     * Please note that because you can't set settings with this there is no way to know what the filename
106     * that was produced was. It contains a timestamp making it hard to find.
107     *
108     * @Given /^I perform a quick backup of course "(?P<course_fullname_string>(?:[^"]|\\")*)"$/
109     * @param string $backupcourse
110     */
111    public function i_perform_a_quick_backup_of_course($backupcourse) {
112        // We can not use other steps here as we don't know where the provided data
113        // table elements are used, and we need to catch exceptions contantly.
114
115        // Go to homepage.
116        $this->getSession()->visit($this->locate_path('/?redirect=0'));
117
118        // Click the course link.
119        $this->find_link($backupcourse)->click();
120
121        // Click the backup link.
122        $this->find_link(get_string('backup'))->click();
123        $this->wait();
124
125        // Initial settings.
126        $this->find_button(get_string('jumptofinalstep', 'backup'))->press();
127        $this->wait();
128
129        // Waiting for it to finish.
130        $this->wait(self::EXTENDED_TIMEOUT);
131
132        // Last backup continue button.
133        $this->find_button(get_string('backupstage16action', 'backup'))->press();
134    }
135
136    /**
137     * Imports the specified origin course into the other course using the provided options.
138     *
139     * Keeping it separatelly from backup & restore, it the number of
140     * steps and duplicate code becomes bigger a common method should
141     * be generalized.
142     *
143     * @Given /^I import "(?P<from_course_fullname_string>(?:[^"]|\\")*)" course into "(?P<to_course_fullname_string>(?:[^"]|\\")*)" course using this options:$/
144     * @param string $fromcourse
145     * @param string $tocourse
146     * @param TableNode $options
147     */
148    public function i_import_course_into_course($fromcourse, $tocourse, $options = false) {
149
150        // We can not use other steps here as we don't know where the provided data
151        // table elements are used, and we need to catch exceptions contantly.
152
153        // Go to homepage.
154        $this->getSession()->visit($this->locate_path('/?redirect=0'));
155        $this->wait();
156
157        // Click the course link.
158        $this->find_link($tocourse)->click();
159        $this->wait();
160
161        // Click the import link.
162        $this->navigate_to_course_settings_link('import');
163        $this->wait();
164
165        // Select the course.
166        $exception = new ExpectationException('"' . $fromcourse . '" course not found in the list of courses to import from',
167            $this->getSession());
168
169        // The argument should be converted to an xpath literal.
170        $fromcourse = $this->getSession()->getSelectorsHandler()->xpathLiteral($fromcourse);
171        $xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' ics-results ')]" .
172            "/descendant::tr[contains(., $fromcourse)]" .
173            "/descendant::input[@type='radio']";
174        $radionode = $this->find('xpath', $xpath, $exception);
175        $radiofield = new behat_form_field($this->getSession(), $radionode);
176        $radiofield->set_value(1);
177
178        $this->find_button(get_string('continue'))->press();
179        $this->wait();
180
181        // Initial settings.
182        $this->fill_backup_restore_form($this->get_step_options($options, "Initial"));
183        $this->find_button(get_string('importbackupstage1action', 'backup'))->press();
184        $this->wait();
185
186        // Schema settings.
187        $this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
188        $this->find_button(get_string('importbackupstage2action', 'backup'))->press();
189        $this->wait();
190
191        // Run it.
192        $this->find_button(get_string('importbackupstage4action', 'backup'))->press();
193        $this->wait(self::EXTENDED_TIMEOUT);
194
195        // Continue and redirect to 'to' course.
196        $this->find_button(get_string('continue'))->press();
197    }
198
199    /**
200     * Restores the backup into the specified course and the provided options.
201     *
202     * You should be in the 'Restore' page where the backup is.
203     *
204     * @Given /^I restore "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into "(?P<existing_course_fullname_string>(?:[^"]|\\")*)" course using this options:$/
205     * @param string $backupfilename
206     * @param string $existingcourse
207     * @param TableNode $options Restore forms options or false if no options provided
208     */
209    public function i_restore_backup_into_course_using_this_options($backupfilename, $existingcourse, $options = false) {
210
211        // Confirm restore.
212        $this->select_backup($backupfilename);
213
214        // The argument should be converted to an xpath literal.
215        $existingcourse = $this->getSession()->getSelectorsHandler()->xpathLiteral($existingcourse);
216
217        // Selecting the specified course (we can not call behat_forms::select_radio here as is in another behat subcontext).
218        $radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-existing-course ')]" .
219            "/descendant::div[@class='restore-course-search']" .
220            "/descendant::tr[contains(., $existingcourse)]" .
221            "/descendant::input[@type='radio']");
222        $radionode->check();
223        $radionode->click();
224
225        // Pressing the continue button of the restore into an existing course section.
226        $continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-existing-course ')]" .
227            "/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
228        $continuenode->click();
229        $this->wait();
230
231        // Common restore process using provided key/value options.
232        $this->process_restore($options);
233    }
234
235    /**
236     * Restores the specified backup into a new course using the provided options.
237     *
238     * You should be in the 'Restore' page where the backup is.
239     *
240     * @Given /^I restore "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into a new course using this options:$/
241     * @param string $backupfilename
242     * @param TableNode $options Restore forms options or false if no options provided
243     */
244    public function i_restore_backup_into_a_new_course_using_this_options($backupfilename, $options = false) {
245
246        // Confirm restore.
247        $this->select_backup($backupfilename);
248
249        // The first category in the list.
250        $radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-new-course ')]" .
251            "/descendant::div[@class='restore-course-search']" .
252            "/descendant::input[@type='radio']");
253        $radionode->check();
254        $radionode->click();
255
256        // Pressing the continue button of the restore into an existing course section.
257        $continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-new-course ')]" .
258            "/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
259        $continuenode->click();
260        $this->wait();
261
262        // Common restore process using provided key/value options.
263        $this->process_restore($options);
264    }
265
266    /**
267     * Merges the backup into the current course using the provided restore options.
268     *
269     * You should be in the 'Restore' page where the backup is.
270     *
271     * @Given /^I merge "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into the current course using this options:$/
272     * @param string $backupfilename
273     * @param TableNode $options Restore forms options or false if no options provided
274     */
275    public function i_merge_backup_into_the_current_course($backupfilename, $options = false) {
276
277        // Confirm restore.
278        $this->select_backup($backupfilename);
279
280        // Merge without deleting radio option.
281        $radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
282            "/descendant::input[@type='radio'][@name='target'][@value='1']");
283        $radionode->check();
284        $radionode->click();
285
286        // Pressing the continue button of the restore merging section.
287        $continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
288            "/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
289        $continuenode->click();
290        $this->wait();
291
292        // Common restore process using provided key/value options.
293        $this->process_restore($options);
294    }
295
296    /**
297     * Merges the backup into the current course after deleting this contents, using the provided restore options.
298     *
299     * You should be in the 'Restore' page where the backup is.
300     *
301     * @Given /^I merge "(?P<backup_filename_string>(?:[^"]|\\")*)" backup into the current course after deleting it's contents using this options:$/
302     * @param string $backupfilename
303     * @param TableNode $options Restore forms options or false if no options provided
304     */
305    public function i_merge_backup_into_current_course_deleting_its_contents($backupfilename, $options = false) {
306
307        // Confirm restore.
308        $this->select_backup($backupfilename);
309
310        // Delete contents radio option.
311        $radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
312            "/descendant::input[@type='radio'][@name='target'][@value='0']");
313        $radionode->check();
314        $radionode->click();
315
316        // Pressing the continue button of the restore merging section.
317        $continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
318            "/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
319        $continuenode->click();
320        $this->wait();
321
322        // Common restore process using provided key/value options.
323        $this->process_restore($options);
324    }
325
326    /**
327     * Selects the backup to restore.
328     *
329     * @throws ExpectationException
330     * @param string $backupfilename
331     * @return void
332     */
333    protected function select_backup($backupfilename) {
334
335        // Using xpath as there are other restore links before this one.
336        $exception = new ExpectationException('The "' . $backupfilename . '" backup file can not be found in this page',
337            $this->getSession());
338
339        // The argument should be converted to an xpath literal.
340        $backupfilename = $this->getSession()->getSelectorsHandler()->xpathLiteral($backupfilename);
341
342        $xpath = "//tr[contains(., $backupfilename)]/descendant::a[contains(., '" . get_string('restore') . "')]";
343        $restorelink = $this->find('xpath', $xpath, $exception);
344        $restorelink->click();
345
346        // Confirm the backup contents.
347        $restore = $this->find_button(get_string('continue'))->press();
348    }
349
350    /**
351     * Executes the common steps of all restore processes.
352     *
353     * @param TableNode $options The backup and restore options or false if no options provided
354     * @return void
355     */
356    protected function process_restore($options) {
357
358        // We can not use other steps here as we don't know where the provided data
359        // table elements are used, and we need to catch exceptions contantly.
360
361        // Settings.
362        $this->fill_backup_restore_form($this->get_step_options($options, "Settings"));
363        $this->find_button(get_string('restorestage4action', 'backup'))->press();
364        $this->wait();
365
366        // Schema.
367        $this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
368        $this->find_button(get_string('restorestage8action', 'backup'))->press();
369        $this->wait();
370
371        // Review, no options here.
372        $this->find_button(get_string('restorestage16action', 'backup'))->press();
373        $this->wait();
374
375        // Last restore continue button, redirected to restore course after this.
376        $this->find_button(get_string('restorestage32action', 'backup'))->press();
377
378        // Long wait when waiting for the restore to finish.
379        $this->wait(self::EXTENDED_TIMEOUT);
380    }
381
382    /**
383     * Tries to fill the current page form elements with the provided options.
384     *
385     * This step is slow as it spins over each provided option, we are
386     * not expected to have lots of provided options, anyways, is better
387     * to be conservative and wait for the elements to appear rather than
388     * to have false failures.
389     *
390     * @param TableNode $options The backup and restore options or false if no options provided
391     * @return void
392     */
393    protected function fill_backup_restore_form($options) {
394
395        // Nothing to fill if no options are provided.
396        if (!$options) {
397            return;
398        }
399
400        // If we find any of the provided options in the current form we should set the value.
401        $datahash = $options->getRowsHash();
402        foreach ($datahash as $locator => $value) {
403            $field = behat_field_manager::get_form_field_from_label($locator, $this);
404            $field->set_value($value);
405        }
406    }
407
408    /**
409     * Get the options specific to this step of the backup/restore process.
410     *
411     * @param TableNode $options The options table to filter
412     * @param string $step The name of the step
413     * @return TableNode The filtered options table
414     * @throws ExpectationException
415     */
416    protected function get_step_options($options, $step) {
417        // Nothing to fill if no options are provided.
418        if (!$options) {
419            return;
420        }
421
422        $pageoptions = clone $options;
423
424        $rows = $options->getRows();
425        $newrows = array();
426        foreach ($rows as $k => $data) {
427            if (count($data) !== 3) {
428                // Not enough information to guess the page.
429                throw new ExpectationException("The backup/restore step must be specified for all backup options",
430                    $this->getSession());
431            } else if ($data[0] == $step) {
432                unset($data[0]);
433                $newrows[] = $data;
434            }
435        }
436        $pageoptions->setRows($newrows);
437        return $pageoptions;
438    }
439
440
441    /**
442     * Waits until the DOM and the page Javascript code is ready.
443     *
444     * @param int $timeout The number of seconds that we wait.
445     * @return void
446     */
447    protected function wait($timeout = false) {
448
449        if (!$this->running_javascript()) {
450            return;
451        }
452
453        if (!$timeout) {
454            $timeout = self::TIMEOUT;
455        }
456
457        $this->getSession()->wait($timeout * 1000, self::PAGE_READY_JS);
458    }
459
460}
Note: See TracBrowser for help on using the repository browser.