MDL-43738 behat: More info about how to get/set fields
[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() {
101
fb99ef1d
DM
102 // We ensure that all the editors are loaded and we can interact with them.
103 $this->ensure_editors_are_loaded();
104
74c78e74
DM
105 // We already know that we waited for the DOM and the JS to be loaded, even the editor
106 // so, we will use the reduced timeout as it is a common task and we should save time.
f8f1bdc3
DM
107 try {
108
8cda2e6f 109 // Expand fieldsets link.
74c78e74 110 $xpath = "//div[@class='collapsible-actions']" .
8cda2e6f 111 "/descendant::a[contains(concat(' ', @class, ' '), ' collapseexpand ')]" .
74c78e74
DM
112 "[not(contains(concat(' ', @class, ' '), ' collapse-all '))]";
113 $collapseexpandlink = $this->find('xpath', $xpath, false, false, self::REDUCED_TIMEOUT);
8cda2e6f 114 $collapseexpandlink->click();
f8f1bdc3
DM
115
116 } catch (ElementNotFoundException $e) {
74c78e74
DM
117 // The behat_base::find() method throws an exception if there are no elements,
118 // we should not fail a test because of this. We continue if there are not expandable fields.
f8f1bdc3
DM
119 }
120
121 // Different try & catch as we can have expanded fieldsets with advanced fields on them.
122 try {
123
8cda2e6f
DM
124 // Expand all fields xpath.
125 $showmorexpath = "//a[normalize-space(.)='" . get_string('showmore', 'form') . "']" .
126 "[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]";
f8f1bdc3 127
8cda2e6f 128 // We don't wait here as we already waited when getting the expand fieldsets links.
74c78e74
DM
129 if (!$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath)) {
130 return;
131 }
f8f1bdc3 132
8cda2e6f
DM
133 // Funny thing about this, with findAll() we specify a pattern and each element matching the pattern is added to the array
134 // with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath
135 // anymore (now is a "Show less..." link) so [1] becomes [0], that's why we always click on the first XPath match,
136 // will be always the next one.
f8f1bdc3
DM
137 $iterations = count($showmores);
138 for ($i = 0; $i < $iterations; $i++) {
139 $showmores[0]->click();
140 }
141
142 } catch (ElementNotFoundException $e) {
143 // We continue with the test.
144 }
145
146 }
147
23ebc481 148 /**
a5254141 149 * Sets the specified value to the field.
23ebc481 150 *
decf1e14 151 * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" to "(?P<field_value_string>(?:[^"]|\\")*)"$/
1f9ffbdb 152 * @throws ElementNotFoundException Thrown by behat_base::find
46ac40cd
DM
153 * @param string $field
154 * @param string $value
a5254141 155 * @return void
23ebc481 156 */
a5254141 157 public function i_set_the_field_to($field, $value) {
c3f1e953 158 $this->set_field_value($field, $value);
23ebc481
DM
159 }
160
161 /**
a5254141 162 * Checks, the field matches the value. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
23ebc481 163 *
decf1e14 164 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" matches value "(?P<field_value_string>(?:[^"]|\\")*)"$/
1f9ffbdb 165 * @throws ElementNotFoundException Thrown by behat_base::find
a5254141 166 * @param string $field
46ac40cd 167 * @param string $value
a5254141 168 * @return void
23ebc481 169 */
a5254141 170 public function the_field_matches_value($field, $value) {
23ebc481 171
a5254141 172 $fieldnode = $this->find_field($field);
23ebc481 173
49d91129 174 // Get the field.
a5254141 175 $formfield = behat_field_manager::get_form_field($fieldnode, $this->getSession());
23ebc481
DM
176
177 // Checks if the provided value matches the current field value.
a5254141
DM
178 if (!$formfield->matches($value)) {
179 $fieldvalue = $formfield->get_value();
23ebc481 180 throw new ExpectationException(
a5254141 181 'The \'' . $field . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
23ebc481
DM
182 $this->getSession()
183 );
184 }
185 }
186
c3f1e953 187 /**
a5254141 188 * Checks, the field does not match the value. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
c3f1e953 189 *
decf1e14 190 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" does not match value "(?P<field_value_string>(?:[^"]|\\")*)"$/
c3f1e953
DM
191 * @throws ExpectationException
192 * @throws ElementNotFoundException Thrown by behat_base::find
193 * @param string $field
194 * @param string $value
195 * @return void
196 */
197 public function the_field_does_not_match_value($field, $value) {
198
199 $fieldnode = $this->find_field($field);
200
201 // Get the field.
a5254141 202 $formfield = behat_field_manager::get_form_field($fieldnode, $this->getSession());
c3f1e953
DM
203
204 // Checks if the provided value matches the current field value.
a5254141
DM
205 if ($formfield->matches($value)) {
206 $fieldvalue = $formfield->get_value();
c3f1e953
DM
207 throw new ExpectationException(
208 'The \'' . $field . '\' value matches \'' . $value . '\' and it should not match it' ,
209 $this->getSession()
210 );
211 }
212 }
213
214 /**
a5254141 215 * Checks, the provided field/value matches. More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps.
c3f1e953
DM
216 *
217 * @Then /^the following fields match these values:$/
218 * @throws ExpectationException
a5254141 219 * @param TableNode $data Pairs of | field | value |
c3f1e953
DM
220 */
221 public function the_following_fields_match_these_values(TableNode $data) {
222
223 // Expand all fields in case we have.
224 $this->expand_all_fields();
225
226 $datahash = $data->getRowsHash();
227
228 // The action depends on the field type.
229 foreach ($datahash as $locator => $value) {
a5254141 230 $this->the_field_matches_value($locator, $value);
c3f1e953
DM
231 }
232 }
233
234 /**
decf1e14 235 * 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
236 *
237 * @Then /^the following fields do not match these values:$/
238 * @throws ExpectationException
a5254141 239 * @param TableNode $data Pairs of | field | value |
c3f1e953
DM
240 */
241 public function the_following_fields_do_not_match_these_values(TableNode $data) {
242
243 // Expand all fields in case we have.
244 $this->expand_all_fields();
245
246 $datahash = $data->getRowsHash();
247
248 // The action depends on the field type.
249 foreach ($datahash as $locator => $value) {
250 $this->the_field_does_not_match_value($locator, $value);
251 }
252 }
253
23ebc481
DM
254 /**
255 * Checks, that given select box contains the specified option.
256 *
23ebc481 257 * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should contain "(?P<option_string>(?:[^"]|\\")*)"$/
1f9ffbdb
DM
258 * @throws ExpectationException
259 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481 260 * @param string $select The select element name
5f66d46e
EL
261 * @param string $option The option text/value. Plain value or comma separated
262 * values if multiple. Commas in multiple values escaped with backslash.
23ebc481
DM
263 */
264 public function the_select_box_should_contain($select, $option) {
265
1f9ffbdb 266 $selectnode = $this->find_field($select);
5f66d46e
EL
267 $multiple = $selectnode->hasAttribute('multiple');
268 $optionsarr = array(); // Array of passed value/text options to test.
23ebc481 269
5f66d46e
EL
270 if ($multiple) {
271 // Can pass multiple comma separated, with valuable commas escaped with backslash.
272 foreach (preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', $option)) as $opt) {
273 $optionsarr[] = trim($opt);
274 }
275 } else {
276 // Only one option has been passed.
277 $optionsarr[] = trim($option);
278 }
279
280 // Now get all the values and texts in the select.
281 $options = $selectnode->findAll('xpath', '//option');
282 $values = array();
283 foreach ($options as $opt) {
284 $values[trim($opt->getValue())] = trim($opt->getText());
23ebc481
DM
285 }
286
5f66d46e
EL
287 foreach ($optionsarr as $opt) {
288 // Verify every option is a valid text or value.
289 if (!in_array($opt, $values) && !array_key_exists($opt, $values)) {
290 throw new ExpectationException(
291 'The select box "' . $select . '" does not contain the option "' . $opt . '"',
292 $this->getSession()
293 );
294 }
295 }
23ebc481
DM
296 }
297
298 /**
299 * Checks, that given select box does not contain the specified option.
300 *
23ebc481 301 * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should not contain "(?P<option_string>(?:[^"]|\\")*)"$/
1f9ffbdb
DM
302 * @throws ExpectationException
303 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481 304 * @param string $select The select element name
5f66d46e
EL
305 * @param string $option The option text/value. Plain value or comma separated
306 * values if multiple. Commas in multiple values escaped with backslash.
23ebc481
DM
307 */
308 public function the_select_box_should_not_contain($select, $option) {
309
1f9ffbdb 310 $selectnode = $this->find_field($select);
5f66d46e
EL
311 $multiple = $selectnode->hasAttribute('multiple');
312 $optionsarr = array(); // Array of passed value/text options to test.
23ebc481 313
5f66d46e
EL
314 if ($multiple) {
315 // Can pass multiple comma separated, with valuable commas escaped with backslash.
316 foreach (preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', $option)) as $opt) {
317 $optionsarr[] = trim($opt);
318 }
319 } else {
320 // Only one option has been passed.
321 $optionsarr[] = trim($option);
322 }
323
324 // Now get all the values and texts in the select.
325 $options = $selectnode->findAll('xpath', '//option');
326 $values = array();
327 foreach ($options as $opt) {
328 $values[trim($opt->getValue())] = trim($opt->getText());
329 }
330
331 foreach ($optionsarr as $opt) {
332 // Verify every option is not a valid text or value.
333 if (in_array($opt, $values) || array_key_exists($opt, $values)) {
334 throw new ExpectationException(
335 'The select box "' . $select . '" contains the option "' . $opt . '"',
336 $this->getSession()
337 );
338 }
339 }
340 }
341
342 /**
c3f1e953 343 * Generic field setter.
5f66d46e 344 *
c3f1e953
DM
345 * Internal API method, a generic *I set "VALUE" to "FIELD" field*
346 * could be created based on it.
5f66d46e 347 *
c3f1e953
DM
348 * @param string $fieldlocator The pointer to the field, it will depend on the field type.
349 * @param string $value
350 * @return void
5f66d46e 351 */
c3f1e953 352 protected function set_field_value($fieldlocator, $value) {
5f66d46e 353
c3f1e953 354 $node = $this->find_field($fieldlocator);
5f66d46e 355
c3f1e953
DM
356 // We delegate to behat_form_field class, it will
357 // guess the type properly as it is a select tag.
358 $field = behat_field_manager::get_form_field($node, $this->getSession());
359 $field->set_value($value);
23ebc481
DM
360 }
361
23ebc481 362}