MDL-49205 behat: fix I set the field with xpath fail message.
[moodle.git] / lib / tests / behat / behat_forms.php
CommitLineData
23ebc481
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 * Steps definitions related with forms.
19 *
20 * @package core
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');
a4534dce 29require_once(__DIR__ . '/../../../lib/behat/behat_field_manager.php');
23ebc481
DM
30
31use Behat\Behat\Context\Step\Given as Given,
32 Behat\Behat\Context\Step\When as When,
33 Behat\Behat\Context\Step\Then as Then,
34 Behat\Gherkin\Node\TableNode as TableNode,
35 Behat\Mink\Element\NodeElement as NodeElement,
36 Behat\Mink\Exception\ExpectationException as ExpectationException,
37 Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
38
39/**
40 * Forms-related steps definitions.
41 *
42 * @package core
43 * @category test
44 * @copyright 2012 David MonllaĆ³
45 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 */
47class behat_forms extends behat_base {
48
49 /**
50 * Presses button with specified id|name|title|alt|value.
51 *
23ebc481 52 * @When /^I press "(?P<button_string>(?:[^"]|\\")*)"$/
1f9ffbdb 53 * @throws ElementNotFoundException Thrown by behat_base::find
46ac40cd 54 * @param string $button
23ebc481
DM
55 */
56 public function press_button($button) {
1f9ffbdb
DM
57
58 // Ensures the button is present.
59 $buttonnode = $this->find_button($button);
60 $buttonnode->press();
23ebc481
DM
61 }
62
63 /**
a5254141 64 * Fills a form with field/value data. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
23ebc481 65 *
a5254141 66 * @Given /^I set the following fields to these values:$/
1f9ffbdb 67 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481
DM
68 * @param TableNode $data
69 */
a5254141 70 public function i_set_the_following_fields_to_these_values(TableNode $data) {
23ebc481 71
f8f1bdc3
DM
72 // Expand all fields in case we have.
73 $this->expand_all_fields();
74
23ebc481
DM
75 $datahash = $data->getRowsHash();
76
77 // The action depends on the field type.
78 foreach ($datahash as $locator => $value) {
a5254141 79 $this->set_field_value($locator, $value);
23ebc481
DM
80 }
81 }
82
f8f1bdc3
DM
83 /**
84 * Expands all moodleform's fields, including collapsed fieldsets and advanced fields if they are present.
85 * @Given /^I expand all fieldsets$/
86 */
87 public function i_expand_all_fieldsets() {
88 $this->expand_all_fields();
89 }
90
91 /**
92 * Expands all moodle form fieldsets if they exists.
93 *
94 * Externalized from i_expand_all_fields to call it from
95 * other form-related steps without having to use steps-group calls.
96 *
97 * @throws ElementNotFoundException Thrown by behat_base::find_all
98 * @return void
99 */
100 protected function expand_all_fields() {
20153f63
RT
101 // Expand only if JS mode, else not needed.
102 if (!$this->running_javascript()) {
103 return;
104 }
f8f1bdc3 105
74c78e74
DM
106 // We already know that we waited for the DOM and the JS to be loaded, even the editor
107 // so, we will use the reduced timeout as it is a common task and we should save time.
f8f1bdc3
DM
108 try {
109
8cda2e6f 110 // Expand fieldsets link.
74c78e74 111 $xpath = "//div[@class='collapsible-actions']" .
8cda2e6f 112 "/descendant::a[contains(concat(' ', @class, ' '), ' collapseexpand ')]" .
74c78e74
DM
113 "[not(contains(concat(' ', @class, ' '), ' collapse-all '))]";
114 $collapseexpandlink = $this->find('xpath', $xpath, false, false, self::REDUCED_TIMEOUT);
8cda2e6f 115 $collapseexpandlink->click();
f8f1bdc3
DM
116
117 } catch (ElementNotFoundException $e) {
74c78e74
DM
118 // The behat_base::find() method throws an exception if there are no elements,
119 // we should not fail a test because of this. We continue if there are not expandable fields.
f8f1bdc3
DM
120 }
121
122 // Different try & catch as we can have expanded fieldsets with advanced fields on them.
123 try {
124
8cda2e6f
DM
125 // Expand all fields xpath.
126 $showmorexpath = "//a[normalize-space(.)='" . get_string('showmore', 'form') . "']" .
127 "[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]";
f8f1bdc3 128
8cda2e6f 129 // We don't wait here as we already waited when getting the expand fieldsets links.
74c78e74
DM
130 if (!$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath)) {
131 return;
132 }
f8f1bdc3 133
8cda2e6f
DM
134 // Funny thing about this, with findAll() we specify a pattern and each element matching the pattern is added to the array
135 // with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath
136 // anymore (now is a "Show less..." link) so [1] becomes [0], that's why we always click on the first XPath match,
137 // will be always the next one.
f8f1bdc3
DM
138 $iterations = count($showmores);
139 for ($i = 0; $i < $iterations; $i++) {
140 $showmores[0]->click();
141 }
142
143 } catch (ElementNotFoundException $e) {
144 // We continue with the test.
145 }
146
147 }
148
23ebc481 149 /**
a5254141 150 * Sets the specified value to the field.
23ebc481 151 *
decf1e14 152 * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" to "(?P<field_value_string>(?:[^"]|\\")*)"$/
1f9ffbdb 153 * @throws ElementNotFoundException Thrown by behat_base::find
46ac40cd
DM
154 * @param string $field
155 * @param string $value
a5254141 156 * @return void
23ebc481 157 */
a5254141 158 public function i_set_the_field_to($field, $value) {
c3f1e953 159 $this->set_field_value($field, $value);
23ebc481
DM
160 }
161
6c396b6b
RT
162 /**
163 * Sets the specified value to the field with xpath.
164 *
165 * @Given /^I set the field with xpath "(?P<fieldxpath_string>(?:[^"]|\\")*)" to "(?P<field_value_string>(?:[^"]|\\")*)"$/
166 * @throws ElementNotFoundException Thrown by behat_base::find
167 * @param string $field
168 * @param string $value
169 * @return void
170 */
171 public function i_set_the_field_with_xpath_to($fieldxpath, $value) {
f0edd9d8 172 $fieldNode = $this->find('xpath', $fieldxpath);
6c396b6b
RT
173 $field = behat_field_manager::get_form_field($fieldNode, $this->getSession());
174 $field->set_value($value);
175 }
176
23ebc481 177 /**
a5254141 178 * Checks, the field matches the value. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
23ebc481 179 *
decf1e14 180 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" matches value "(?P<field_value_string>(?:[^"]|\\")*)"$/
1f9ffbdb 181 * @throws ElementNotFoundException Thrown by behat_base::find
a5254141 182 * @param string $field
46ac40cd 183 * @param string $value
a5254141 184 * @return void
23ebc481 185 */
a5254141 186 public function the_field_matches_value($field, $value) {
23ebc481 187
49d91129 188 // Get the field.
af4830a2 189 $formfield = behat_field_manager::get_form_field_from_label($field, $this);
23ebc481
DM
190
191 // Checks if the provided value matches the current field value.
a5254141
DM
192 if (!$formfield->matches($value)) {
193 $fieldvalue = $formfield->get_value();
23ebc481 194 throw new ExpectationException(
a5254141 195 'The \'' . $field . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
23ebc481
DM
196 $this->getSession()
197 );
198 }
199 }
200
c3f1e953 201 /**
a5254141 202 * Checks, the field does not match the value. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
c3f1e953 203 *
decf1e14 204 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" does not match value "(?P<field_value_string>(?:[^"]|\\")*)"$/
c3f1e953
DM
205 * @throws ExpectationException
206 * @throws ElementNotFoundException Thrown by behat_base::find
207 * @param string $field
208 * @param string $value
209 * @return void
210 */
211 public function the_field_does_not_match_value($field, $value) {
212
c3f1e953 213 // Get the field.
af4830a2 214 $formfield = behat_field_manager::get_form_field_from_label($field, $this);
c3f1e953
DM
215
216 // Checks if the provided value matches the current field value.
a5254141
DM
217 if ($formfield->matches($value)) {
218 $fieldvalue = $formfield->get_value();
c3f1e953
DM
219 throw new ExpectationException(
220 'The \'' . $field . '\' value matches \'' . $value . '\' and it should not match it' ,
221 $this->getSession()
222 );
223 }
224 }
225
226 /**
a5254141 227 * Checks, the provided field/value matches. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
c3f1e953
DM
228 *
229 * @Then /^the following fields match these values:$/
230 * @throws ExpectationException
a5254141 231 * @param TableNode $data Pairs of | field | value |
c3f1e953
DM
232 */
233 public function the_following_fields_match_these_values(TableNode $data) {
234
235 // Expand all fields in case we have.
236 $this->expand_all_fields();
237
238 $datahash = $data->getRowsHash();
239
240 // The action depends on the field type.
241 foreach ($datahash as $locator => $value) {
a5254141 242 $this->the_field_matches_value($locator, $value);
c3f1e953
DM
243 }
244 }
245
246 /**
decf1e14 247 * Checks that the provided field/value pairs don't match. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
c3f1e953
DM
248 *
249 * @Then /^the following fields do not match these values:$/
250 * @throws ExpectationException
a5254141 251 * @param TableNode $data Pairs of | field | value |
c3f1e953
DM
252 */
253 public function the_following_fields_do_not_match_these_values(TableNode $data) {
254
255 // Expand all fields in case we have.
256 $this->expand_all_fields();
257
258 $datahash = $data->getRowsHash();
259
260 // The action depends on the field type.
261 foreach ($datahash as $locator => $value) {
262 $this->the_field_does_not_match_value($locator, $value);
263 }
264 }
265
23ebc481
DM
266 /**
267 * Checks, that given select box contains the specified option.
268 *
23ebc481 269 * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should contain "(?P<option_string>(?:[^"]|\\")*)"$/
1f9ffbdb
DM
270 * @throws ExpectationException
271 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481 272 * @param string $select The select element name
5f66d46e
EL
273 * @param string $option The option text/value. Plain value or comma separated
274 * values if multiple. Commas in multiple values escaped with backslash.
23ebc481
DM
275 */
276 public function the_select_box_should_contain($select, $option) {
277
1f9ffbdb 278 $selectnode = $this->find_field($select);
5f66d46e
EL
279 $multiple = $selectnode->hasAttribute('multiple');
280 $optionsarr = array(); // Array of passed value/text options to test.
23ebc481 281
5f66d46e
EL
282 if ($multiple) {
283 // Can pass multiple comma separated, with valuable commas escaped with backslash.
284 foreach (preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', $option)) as $opt) {
285 $optionsarr[] = trim($opt);
286 }
287 } else {
288 // Only one option has been passed.
289 $optionsarr[] = trim($option);
290 }
291
292 // Now get all the values and texts in the select.
293 $options = $selectnode->findAll('xpath', '//option');
294 $values = array();
295 foreach ($options as $opt) {
296 $values[trim($opt->getValue())] = trim($opt->getText());
23ebc481
DM
297 }
298
5f66d46e
EL
299 foreach ($optionsarr as $opt) {
300 // Verify every option is a valid text or value.
301 if (!in_array($opt, $values) && !array_key_exists($opt, $values)) {
302 throw new ExpectationException(
303 'The select box "' . $select . '" does not contain the option "' . $opt . '"',
304 $this->getSession()
305 );
306 }
307 }
23ebc481
DM
308 }
309
310 /**
311 * Checks, that given select box does not contain the specified option.
312 *
23ebc481 313 * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should not contain "(?P<option_string>(?:[^"]|\\")*)"$/
1f9ffbdb
DM
314 * @throws ExpectationException
315 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481 316 * @param string $select The select element name
5f66d46e
EL
317 * @param string $option The option text/value. Plain value or comma separated
318 * values if multiple. Commas in multiple values escaped with backslash.
23ebc481
DM
319 */
320 public function the_select_box_should_not_contain($select, $option) {
321
1f9ffbdb 322 $selectnode = $this->find_field($select);
5f66d46e
EL
323 $multiple = $selectnode->hasAttribute('multiple');
324 $optionsarr = array(); // Array of passed value/text options to test.
23ebc481 325
5f66d46e
EL
326 if ($multiple) {
327 // Can pass multiple comma separated, with valuable commas escaped with backslash.
328 foreach (preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', $option)) as $opt) {
329 $optionsarr[] = trim($opt);
330 }
331 } else {
332 // Only one option has been passed.
333 $optionsarr[] = trim($option);
334 }
335
336 // Now get all the values and texts in the select.
337 $options = $selectnode->findAll('xpath', '//option');
338 $values = array();
339 foreach ($options as $opt) {
340 $values[trim($opt->getValue())] = trim($opt->getText());
341 }
342
343 foreach ($optionsarr as $opt) {
344 // Verify every option is not a valid text or value.
345 if (in_array($opt, $values) || array_key_exists($opt, $values)) {
346 throw new ExpectationException(
347 'The select box "' . $select . '" contains the option "' . $opt . '"',
348 $this->getSession()
349 );
350 }
351 }
352 }
353
354 /**
c3f1e953 355 * Generic field setter.
5f66d46e 356 *
c3f1e953
DM
357 * Internal API method, a generic *I set "VALUE" to "FIELD" field*
358 * could be created based on it.
5f66d46e 359 *
c3f1e953
DM
360 * @param string $fieldlocator The pointer to the field, it will depend on the field type.
361 * @param string $value
362 * @return void
5f66d46e 363 */
c3f1e953 364 protected function set_field_value($fieldlocator, $value) {
5f66d46e 365
c3f1e953
DM
366 // We delegate to behat_form_field class, it will
367 // guess the type properly as it is a select tag.
af4830a2 368 $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this);
c3f1e953 369 $field->set_value($value);
23ebc481
DM
370 }
371
23ebc481 372}