MDL-69160 behat: Add form field setter step
[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 30
1f09dea4
AN
31use Behat\Gherkin\Node\{TableNode, PyStringNode};
32use Behat\Mink\Element\NodeElement;
33use Behat\Mink\Exception\{ElementNotFoundException, ExpectationException};
23ebc481
DM
34
35/**
36 * Forms-related steps definitions.
37 *
920a3500
TH
38 * Note, Behat tests to verify that the steps defined here work as advertised
39 * are kept in admin/tool/behat/tests/behat.
40 *
23ebc481
DM
41 * @package core
42 * @category test
43 * @copyright 2012 David MonllaĆ³
44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 */
46class behat_forms extends behat_base {
47
48 /**
49 * Presses button with specified id|name|title|alt|value.
50 *
23ebc481 51 * @When /^I press "(?P<button_string>(?:[^"]|\\")*)"$/
1f9ffbdb 52 * @throws ElementNotFoundException Thrown by behat_base::find
46ac40cd 53 * @param string $button
23ebc481
DM
54 */
55 public function press_button($button) {
de316e8e 56 $this->execute('behat_general::i_click_on', [$button, 'button']);
23ebc481
DM
57 }
58
1ef6a5e3
RT
59 /**
60 * Press button with specified id|name|title|alt|value and switch to main window.
61 *
62 * @When /^I press "(?P<button_string>(?:[^"]|\\")*)" and switch to main window$/
63 * @throws ElementNotFoundException Thrown by behat_base::find
64 * @param string $button
65 */
66 public function press_button_and_switch_to_main_window($button) {
67 // Ensures the button is present, before pressing.
68 $buttonnode = $this->find_button($button);
69 $buttonnode->press();
70
71 // Switch to main window.
72 $this->getSession()->switchToWindow(behat_general::MAIN_WINDOW_NAME);
73 }
74
23ebc481 75 /**
d1ac356a 76 * Fills a form with field/value data.
23ebc481 77 *
a5254141 78 * @Given /^I set the following fields to these values:$/
1f9ffbdb 79 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481
DM
80 * @param TableNode $data
81 */
a5254141 82 public function i_set_the_following_fields_to_these_values(TableNode $data) {
23ebc481 83
f8f1bdc3
DM
84 // Expand all fields in case we have.
85 $this->expand_all_fields();
86
23ebc481
DM
87 $datahash = $data->getRowsHash();
88
89 // The action depends on the field type.
90 foreach ($datahash as $locator => $value) {
a5254141 91 $this->set_field_value($locator, $value);
23ebc481
DM
92 }
93 }
94
920a3500
TH
95 /**
96 * Fills a form with field/value data.
97 *
98 * @Given /^I set the following fields in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" to these values:$/
99 * @throws ElementNotFoundException Thrown by behat_base::find
100 * @param string $containerelement Element we look in
101 * @param string $containerselectortype The type of selector where we look in
102 * @param TableNode $data
103 */
104 public function i_set_the_following_fields_in_container_to_these_values(
105 $containerelement, $containerselectortype, TableNode $data) {
106
107 // Expand all fields in case we have.
108 $this->expand_all_fields();
109
110 $datahash = $data->getRowsHash();
111
112 // The action depends on the field type.
113 foreach ($datahash as $locator => $value) {
114 $this->set_field_value_in_container($locator, $value, $containerselectortype, $containerelement);
115 }
116 }
117
f8f1bdc3
DM
118 /**
119 * Expands all moodleform's fields, including collapsed fieldsets and advanced fields if they are present.
120 * @Given /^I expand all fieldsets$/
121 */
122 public function i_expand_all_fieldsets() {
123 $this->expand_all_fields();
124 }
125
126 /**
127 * Expands all moodle form fieldsets if they exists.
128 *
129 * Externalized from i_expand_all_fields to call it from
130 * other form-related steps without having to use steps-group calls.
131 *
132 * @throws ElementNotFoundException Thrown by behat_base::find_all
133 * @return void
134 */
135 protected function expand_all_fields() {
20153f63
RT
136 // Expand only if JS mode, else not needed.
137 if (!$this->running_javascript()) {
138 return;
139 }
f8f1bdc3 140
74c78e74
DM
141 // We already know that we waited for the DOM and the JS to be loaded, even the editor
142 // so, we will use the reduced timeout as it is a common task and we should save time.
f8f1bdc3
DM
143 try {
144
1872cfcd
TH
145 // Expand all fieldsets link - which will only be there if there is more than one collapsible section.
146 $expandallxpath = "//div[@class='collapsible-actions']" .
147 "//a[contains(concat(' ', @class, ' '), ' collapseexpand ')]" .
74c78e74 148 "[not(contains(concat(' ', @class, ' '), ' collapse-all '))]";
1872cfcd
TH
149 // Else, look for the first expand fieldset link.
150 $expandonlysection = "//legend[@class='ftoggler']" .
151 "//a[contains(concat(' ', @class, ' '), ' fheader ') and @aria-expanded = 'false']";
152
153 $collapseexpandlink = $this->find('xpath', $expandallxpath . '|' . $expandonlysection,
05a5d547 154 false, false, behat_base::get_reduced_timeout());
8cda2e6f 155 $collapseexpandlink->click();
f8f1bdc3
DM
156
157 } catch (ElementNotFoundException $e) {
74c78e74
DM
158 // The behat_base::find() method throws an exception if there are no elements,
159 // we should not fail a test because of this. We continue if there are not expandable fields.
f8f1bdc3
DM
160 }
161
162 // Different try & catch as we can have expanded fieldsets with advanced fields on them.
163 try {
164
8cda2e6f
DM
165 // Expand all fields xpath.
166 $showmorexpath = "//a[normalize-space(.)='" . get_string('showmore', 'form') . "']" .
167 "[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]";
f8f1bdc3 168
8cda2e6f 169 // We don't wait here as we already waited when getting the expand fieldsets links.
74c78e74
DM
170 if (!$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath)) {
171 return;
172 }
f8f1bdc3 173
7cde2bb3
MN
174 if ($this->getSession()->getDriver() instanceof \DMore\ChromeDriver\ChromeDriver) {
175 // Chrome Driver produces unique xpaths for each element.
176 foreach ($showmores as $showmore) {
177 $showmore->click();
178 }
179 } else {
180 // Funny thing about this, with findAll() we specify a pattern and each element matching the pattern
181 // is added to the array with of xpaths with a [0], [1]... sufix, but when we click on an element it
182 // does not matches the specified xpath anymore (now is a "Show less..." link) so [1] becomes [0],
183 // that's why we always click on the first XPath match, will be always the next one.
184 $iterations = count($showmores);
185 for ($i = 0; $i < $iterations; $i++) {
186 $showmores[0]->click();
187 }
f8f1bdc3
DM
188 }
189
190 } catch (ElementNotFoundException $e) {
191 // We continue with the test.
192 }
193
194 }
195
01e8bfd7
JO
196 /**
197 * Sets the field to wwwroot plus the given path. Include the first slash.
198 *
199 * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" to local url "(?P<field_path_string>(?:[^"]|\\")*)"$/
200 * @throws ElementNotFoundException Thrown by behat_base::find
201 * @param string $field
202 * @param string $path
203 * @return void
204 */
205 public function i_set_the_field_to_local_url($field, $path) {
206 global $CFG;
207 $this->set_field_value($field, $CFG->wwwroot . $path);
208 }
209
23ebc481 210 /**
a5254141 211 * Sets the specified value to the field.
23ebc481 212 *
decf1e14 213 * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" to "(?P<field_value_string>(?:[^"]|\\")*)"$/
1f9ffbdb 214 * @throws ElementNotFoundException Thrown by behat_base::find
46ac40cd
DM
215 * @param string $field
216 * @param string $value
a5254141 217 * @return void
23ebc481 218 */
a5254141 219 public function i_set_the_field_to($field, $value) {
c3f1e953 220 $this->set_field_value($field, $value);
23ebc481
DM
221 }
222
920a3500
TH
223 /**
224 * Sets the specified value to the field.
225 *
226 * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" to "(?P<field_value_string>(?:[^"]|\\")*)"$/
227 * @throws ElementNotFoundException Thrown by behat_base::find
228 * @param string $field
229 * @param string $containerelement Element we look in
230 * @param string $containerselectortype The type of selector where we look in
231 * @param string $value
232 */
233 public function i_set_the_field_in_container_to($field, $containerelement, $containerselectortype, $value) {
234 $this->set_field_value_in_container($field, $value, $containerselectortype, $containerelement);
235 }
236
0cf72524
MG
237 /**
238 * Press the key in the field to trigger the javascript keypress event
239 *
240 * Note that the character key will not actually be typed in the input field
241 *
242 * @Given /^I press key "(?P<key_string>(?:[^"]|\\")*)" in the field "(?P<field_string>(?:[^"]|\\")*)"$/
243 * @throws ElementNotFoundException Thrown by behat_base::find
244 * @param string $key either char-code or character itself,
245 * may optionally be prefixed with ctrl-, alt-, shift- or meta-
246 * @param string $field
247 * @return void
248 */
249 public function i_press_key_in_the_field($key, $field) {
250 if (!$this->running_javascript()) {
8a6900ff 251 throw new DriverException('Key press step is not available with Javascript disabled');
0cf72524
MG
252 }
253 $fld = behat_field_manager::get_form_field_from_label($field, $this);
254 $modifier = null;
255 $char = $key;
256 if (preg_match('/-/', $key)) {
257 list($modifier, $char) = preg_split('/-/', $key, 2);
258 }
259 if (is_numeric($char)) {
260 $char = (int)$char;
261 }
262 $fld->key_press($char, $modifier);
263 }
264
9776f3dc
JO
265 /**
266 * Sets the specified value to the field.
267 *
e259795c 268 * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" to multiline:$/
9776f3dc
JO
269 * @throws ElementNotFoundException Thrown by behat_base::find
270 * @param string $field
271 * @param PyStringNode $value
272 * @return void
273 */
274 public function i_set_the_field_to_multiline($field, PyStringNode $value) {
275 $this->set_field_value($field, (string)$value);
276 }
277
6c396b6b
RT
278 /**
279 * Sets the specified value to the field with xpath.
280 *
281 * @Given /^I set the field with xpath "(?P<fieldxpath_string>(?:[^"]|\\")*)" to "(?P<field_value_string>(?:[^"]|\\")*)"$/
282 * @throws ElementNotFoundException Thrown by behat_base::find
283 * @param string $field
284 * @param string $value
285 * @return void
286 */
287 public function i_set_the_field_with_xpath_to($fieldxpath, $value) {
1f09dea4 288 $this->set_field_node_value($this->find('xpath', $fieldxpath), $value);
6c396b6b
RT
289 }
290
23ebc481 291 /**
d1ac356a 292 * Checks, the field matches the value.
23ebc481 293 *
decf1e14 294 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" matches value "(?P<field_value_string>(?:[^"]|\\")*)"$/
1f9ffbdb 295 * @throws ElementNotFoundException Thrown by behat_base::find
a5254141 296 * @param string $field
46ac40cd 297 * @param string $value
a5254141 298 * @return void
23ebc481 299 */
a5254141 300 public function the_field_matches_value($field, $value) {
23ebc481 301
49d91129 302 // Get the field.
af4830a2 303 $formfield = behat_field_manager::get_form_field_from_label($field, $this);
23ebc481
DM
304
305 // Checks if the provided value matches the current field value.
a5254141
DM
306 if (!$formfield->matches($value)) {
307 $fieldvalue = $formfield->get_value();
23ebc481 308 throw new ExpectationException(
a5254141 309 'The \'' . $field . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
d9fddb0b
AH
310 $this->getSession()
311 );
312 }
313 }
314
315 /**
d1ac356a 316 * Checks, the field does not match the value.
267033a9
T
317 *
318 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" does not match value "(?P<field_value_string>(?:[^"]|\\")*)"$/
319 * @throws ExpectationException
320 * @throws ElementNotFoundException Thrown by behat_base::find
321 * @param string $field
322 * @param string $value
267033a9
T
323 */
324 public function the_field_does_not_match_value($field, $value) {
325
326 // Get the field.
327 $formfield = behat_field_manager::get_form_field_from_label($field, $this);
328
329 // Checks if the provided value matches the current field value.
330 if ($formfield->matches($value)) {
331 throw new ExpectationException(
332 'The \'' . $field . '\' value matches \'' . $value . '\' and it should not match it' ,
333 $this->getSession()
334 );
335 }
336 }
337
920a3500
TH
338 /**
339 * Checks, the field matches the value.
340 *
341 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" matches value "(?P<field_value_string>(?:[^"]|\\")*)"$/
342 * @throws ElementNotFoundException Thrown by behat_base::find
343 * @param string $field
344 * @param string $containerelement Element we look in
345 * @param string $containerselectortype The type of selector where we look in
346 * @param string $value
347 */
348 public function the_field_in_container_matches_value($field, $containerelement, $containerselectortype, $value) {
349
350 // Get the field.
351 $node = $this->get_node_in_container('field', $field, $containerselectortype, $containerelement);
352 $formfield = behat_field_manager::get_form_field($node, $this->getSession());
353
354 // Checks if the provided value matches the current field value.
355 if (!$formfield->matches($value)) {
356 $fieldvalue = $formfield->get_value();
357 throw new ExpectationException(
358 'The \'' . $field . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
359 $this->getSession()
360 );
361 }
362 }
363
364 /**
365 * Checks, the field does not match the value.
366 *
367 * @Then /^the field "(?P<field_string>(?:[^"]|\\")*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" does not match value "(?P<field_value_string>(?:[^"]|\\")*)"$/
368 * @throws ExpectationException
369 * @throws ElementNotFoundException Thrown by behat_base::find
370 * @param string $field
371 * @param string $containerelement Element we look in
372 * @param string $containerselectortype The type of selector where we look in
373 * @param string $value
374 */
375 public function the_field_in_container_does_not_match_value($field, $containerelement, $containerselectortype, $value) {
376
377 // Get the field.
378 $node = $this->get_node_in_container('field', $field, $containerselectortype, $containerelement);
379 $formfield = behat_field_manager::get_form_field($node, $this->getSession());
380
381 // Checks if the provided value matches the current field value.
382 if ($formfield->matches($value)) {
383 throw new ExpectationException(
384 'The \'' . $field . '\' value matches \'' . $value . '\' and it should not match it' ,
385 $this->getSession()
386 );
387 }
388 }
389
267033a9
T
390 /**
391 * Checks, the field matches the value.
d9fddb0b 392 *
267033a9
T
393 * @Then /^the field with xpath "(?P<xpath_string>(?:[^"]|\\")*)" matches value "(?P<field_value_string>(?:[^"]|\\")*)"$/
394 * @throws ExpectationException
d9fddb0b
AH
395 * @throws ElementNotFoundException Thrown by behat_base::find
396 * @param string $fieldxpath
397 * @param string $value
398 * @return void
399 */
400 public function the_field_with_xpath_matches_value($fieldxpath, $value) {
401
402 // Get the field.
403 $fieldnode = $this->find('xpath', $fieldxpath);
404 $formfield = behat_field_manager::get_form_field($fieldnode, $this->getSession());
405
406 // Checks if the provided value matches the current field value.
407 if (!$formfield->matches($value)) {
408 $fieldvalue = $formfield->get_value();
409 throw new ExpectationException(
410 'The \'' . $fieldxpath . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
23ebc481
DM
411 $this->getSession()
412 );
413 }
414 }
415
c3f1e953 416 /**
267033a9 417 * Checks, the field does not match the value.
c3f1e953 418 *
267033a9 419 * @Then /^the field with xpath "(?P<xpath_string>(?:[^"]|\\")*)" does not match value "(?P<field_value_string>(?:[^"]|\\")*)"$/
c3f1e953
DM
420 * @throws ExpectationException
421 * @throws ElementNotFoundException Thrown by behat_base::find
267033a9 422 * @param string $fieldxpath
c3f1e953
DM
423 * @param string $value
424 * @return void
425 */
267033a9 426 public function the_field_with_xpath_does_not_match_value($fieldxpath, $value) {
c3f1e953 427
c3f1e953 428 // Get the field.
267033a9
T
429 $fieldnode = $this->find('xpath', $fieldxpath);
430 $formfield = behat_field_manager::get_form_field($fieldnode, $this->getSession());
c3f1e953
DM
431
432 // Checks if the provided value matches the current field value.
a5254141 433 if ($formfield->matches($value)) {
c3f1e953 434 throw new ExpectationException(
267033a9 435 'The \'' . $fieldxpath . '\' value matches \'' . $value . '\' and it should not match it' ,
c3f1e953
DM
436 $this->getSession()
437 );
438 }
439 }
440
441 /**
d1ac356a 442 * Checks, the provided field/value matches.
c3f1e953
DM
443 *
444 * @Then /^the following fields match these values:$/
445 * @throws ExpectationException
a5254141 446 * @param TableNode $data Pairs of | field | value |
c3f1e953
DM
447 */
448 public function the_following_fields_match_these_values(TableNode $data) {
449
450 // Expand all fields in case we have.
451 $this->expand_all_fields();
452
453 $datahash = $data->getRowsHash();
454
455 // The action depends on the field type.
456 foreach ($datahash as $locator => $value) {
a5254141 457 $this->the_field_matches_value($locator, $value);
c3f1e953
DM
458 }
459 }
460
461 /**
d1ac356a 462 * Checks that the provided field/value pairs don't match.
c3f1e953
DM
463 *
464 * @Then /^the following fields do not match these values:$/
465 * @throws ExpectationException
a5254141 466 * @param TableNode $data Pairs of | field | value |
c3f1e953
DM
467 */
468 public function the_following_fields_do_not_match_these_values(TableNode $data) {
469
470 // Expand all fields in case we have.
471 $this->expand_all_fields();
472
473 $datahash = $data->getRowsHash();
474
475 // The action depends on the field type.
476 foreach ($datahash as $locator => $value) {
477 $this->the_field_does_not_match_value($locator, $value);
478 }
479 }
480
920a3500
TH
481 /**
482 * Checks, the provided field/value matches.
483 *
484 * @Then /^the following fields in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" match these values:$/
485 * @throws ExpectationException
486 * @param string $containerelement Element we look in
487 * @param string $containerselectortype The type of selector where we look in
488 * @param TableNode $data Pairs of | field | value |
489 */
490 public function the_following_fields_in_container_match_these_values(
491 $containerelement, $containerselectortype, TableNode $data) {
492
493 // Expand all fields in case we have.
494 $this->expand_all_fields();
495
496 $datahash = $data->getRowsHash();
497
498 // The action depends on the field type.
499 foreach ($datahash as $locator => $value) {
500 $this->the_field_in_container_matches_value($locator, $containerelement, $containerselectortype, $value);
501 }
502 }
503
504 /**
505 * Checks that the provided field/value pairs don't match.
506 *
507 * @Then /^the following fields in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" do not match these values:$/
508 * @throws ExpectationException
509 * @param string $containerelement Element we look in
510 * @param string $containerselectortype The type of selector where we look in
511 * @param TableNode $data Pairs of | field | value |
512 */
513 public function the_following_fields_in_container_do_not_match_these_values(
514 $containerelement, $containerselectortype, TableNode $data) {
515
516 // Expand all fields in case we have.
517 $this->expand_all_fields();
518
519 $datahash = $data->getRowsHash();
520
521 // The action depends on the field type.
522 foreach ($datahash as $locator => $value) {
523 $this->the_field_in_container_does_not_match_value($locator, $containerelement, $containerselectortype, $value);
524 }
525 }
526
23ebc481
DM
527 /**
528 * Checks, that given select box contains the specified option.
529 *
23ebc481 530 * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should contain "(?P<option_string>(?:[^"]|\\")*)"$/
1f9ffbdb
DM
531 * @throws ExpectationException
532 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481 533 * @param string $select The select element name
5f66d46e
EL
534 * @param string $option The option text/value. Plain value or comma separated
535 * values if multiple. Commas in multiple values escaped with backslash.
23ebc481
DM
536 */
537 public function the_select_box_should_contain($select, $option) {
538
1f9ffbdb 539 $selectnode = $this->find_field($select);
5f66d46e
EL
540 $multiple = $selectnode->hasAttribute('multiple');
541 $optionsarr = array(); // Array of passed value/text options to test.
23ebc481 542
5f66d46e
EL
543 if ($multiple) {
544 // Can pass multiple comma separated, with valuable commas escaped with backslash.
545 foreach (preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', $option)) as $opt) {
546 $optionsarr[] = trim($opt);
547 }
548 } else {
549 // Only one option has been passed.
550 $optionsarr[] = trim($option);
551 }
552
553 // Now get all the values and texts in the select.
554 $options = $selectnode->findAll('xpath', '//option');
555 $values = array();
556 foreach ($options as $opt) {
557 $values[trim($opt->getValue())] = trim($opt->getText());
23ebc481
DM
558 }
559
5f66d46e
EL
560 foreach ($optionsarr as $opt) {
561 // Verify every option is a valid text or value.
562 if (!in_array($opt, $values) && !array_key_exists($opt, $values)) {
563 throw new ExpectationException(
564 'The select box "' . $select . '" does not contain the option "' . $opt . '"',
565 $this->getSession()
566 );
567 }
568 }
23ebc481
DM
569 }
570
571 /**
572 * Checks, that given select box does not contain the specified option.
573 *
23ebc481 574 * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should not contain "(?P<option_string>(?:[^"]|\\")*)"$/
1f9ffbdb
DM
575 * @throws ExpectationException
576 * @throws ElementNotFoundException Thrown by behat_base::find
23ebc481 577 * @param string $select The select element name
5f66d46e
EL
578 * @param string $option The option text/value. Plain value or comma separated
579 * values if multiple. Commas in multiple values escaped with backslash.
23ebc481
DM
580 */
581 public function the_select_box_should_not_contain($select, $option) {
582
1f9ffbdb 583 $selectnode = $this->find_field($select);
5f66d46e
EL
584 $multiple = $selectnode->hasAttribute('multiple');
585 $optionsarr = array(); // Array of passed value/text options to test.
23ebc481 586
5f66d46e
EL
587 if ($multiple) {
588 // Can pass multiple comma separated, with valuable commas escaped with backslash.
589 foreach (preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', $option)) as $opt) {
590 $optionsarr[] = trim($opt);
591 }
592 } else {
593 // Only one option has been passed.
594 $optionsarr[] = trim($option);
595 }
596
597 // Now get all the values and texts in the select.
598 $options = $selectnode->findAll('xpath', '//option');
599 $values = array();
600 foreach ($options as $opt) {
601 $values[trim($opt->getValue())] = trim($opt->getText());
602 }
603
604 foreach ($optionsarr as $opt) {
605 // Verify every option is not a valid text or value.
606 if (in_array($opt, $values) || array_key_exists($opt, $values)) {
607 throw new ExpectationException(
608 'The select box "' . $select . '" contains the option "' . $opt . '"',
609 $this->getSession()
610 );
611 }
612 }
613 }
614
615 /**
c3f1e953 616 * Generic field setter.
5f66d46e 617 *
c3f1e953
DM
618 * Internal API method, a generic *I set "VALUE" to "FIELD" field*
619 * could be created based on it.
5f66d46e 620 *
c3f1e953
DM
621 * @param string $fieldlocator The pointer to the field, it will depend on the field type.
622 * @param string $value
623 * @return void
5f66d46e 624 */
c3f1e953 625 protected function set_field_value($fieldlocator, $value) {
c3f1e953
DM
626 // We delegate to behat_form_field class, it will
627 // guess the type properly as it is a select tag.
af4830a2 628 $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this);
c3f1e953 629 $field->set_value($value);
23ebc481
DM
630 }
631
1f09dea4
AN
632 /**
633 * Generic field setter to be used by chainable steps.
634 *
635 * @param NodeElement $fieldnode
636 * @param string $value
637 */
638 public function set_field_node_value(NodeElement $fieldnode, string $value): void {
639 $this->ensure_node_is_visible($fieldnode);
640 $field = behat_field_manager::get_form_field($fieldnode, $this->getSession());
641 $field->set_value($value);
642 }
643
920a3500
TH
644 /**
645 * Generic field setter.
646 *
647 * Internal API method, a generic *I set "VALUE" to "FIELD" field*
648 * could be created based on it.
649 *
650 * @param string $fieldlocator The pointer to the field, it will depend on the field type.
651 * @param string $value the value to set
652 * @param string $containerselectortype The type of selector where we look in
653 * @param string $containerelement Element we look in
654 */
655 protected function set_field_value_in_container($fieldlocator, $value, $containerselectortype, $containerelement) {
920a3500 656 $node = $this->get_node_in_container('field', $fieldlocator, $containerselectortype, $containerelement);
1f09dea4 657 $this->set_field_node_value($node, $value);
920a3500
TH
658 }
659
2b964e1d
AN
660 /**
661 * Select a value from single select and redirect.
662 *
663 * @Given /^I select "(?P<singleselect_option_string>(?:[^"]|\\")*)" from the "(?P<singleselect_name_string>(?:[^"]|\\")*)" singleselect$/
664 */
665 public function i_select_from_the_singleselect($option, $singleselect) {
eb9ca848
RT
666
667 $this->execute('behat_forms::i_set_the_field_to', array($this->escape($singleselect), $this->escape($option)));
2b964e1d
AN
668
669 if (!$this->running_javascript()) {
bf4c3ee0 670 // Press button in the specified select container.
bc7a5953
RT
671 $containerxpath = "//div[" .
672 "(contains(concat(' ', normalize-space(@class), ' '), ' singleselect ') " .
673 "or contains(concat(' ', normalize-space(@class), ' '), ' urlselect ')".
674 ") and (
675 .//label[contains(normalize-space(string(.)), '" . $singleselect . "')] " .
676 "or .//select[(./@name='" . $singleselect . "' or ./@id='". $singleselect . "')]" .
677 ")]";
bf4c3ee0 678
eb9ca848
RT
679 $this->execute('behat_general::i_click_on_in_the',
680 array(get_string('go'), "button", $containerxpath, "xpath_element")
681 );
2b964e1d 682 }
2b964e1d
AN
683 }
684
dda64b6f
DW
685 /**
686 * Select item from autocomplete list.
687 *
688 * @Given /^I click on "([^"]*)" item in the autocomplete list$/
689 *
690 * @param string $item
691 */
692 public function i_click_on_item_in_the_autocomplete_list($item) {
d29be320 693 $xpathtarget = "//ul[@class='form-autocomplete-suggestions']//*[contains(concat('|', string(.), '|'),'|" . $item . "|')]";
dda64b6f
DW
694
695 $this->execute('behat_general::i_click_on', [$xpathtarget, 'xpath_element']);
696
697 $this->execute('behat_general::i_press_key_in_element', ['13', 'body', 'xpath_element']);
698 }
699
700 /**
701 * Open the auto-complete suggestions list (Assuming there is only one on the page.).
702 *
703 * @Given /^I open the autocomplete suggestions list$/
704 */
705 public function i_open_the_autocomplete_suggestions_list() {
706 $csstarget = ".form-autocomplete-downarrow";
707 $this->execute('behat_general::i_click_on', [$csstarget, 'css_element']);
708 }
0fc30827
HN
709
710 /**
711 * Expand the given autocomplete list
712 *
713 * @Given /^I expand the "(?P<field_string>(?:[^"]|\\")*)" autocomplete$/
714 *
715 * @param string $field Field name
716 */
717 public function i_expand_the_autocomplete($field) {
718 $csstarget = '.form-autocomplete-downarrow';
719 $node = $this->get_node_in_container('css_element', $csstarget, 'form_row', $field);
720 $this->ensure_node_is_visible($node);
721 $node->click();
722 }
723
724 /**
725 * Assert the given option exist in the given autocomplete list
726 *
727 * @Given /^I should see "(?P<option_string>(?:[^"]|\\")*)" in the list of options for the "(?P<field_string>(?:[^"]|\\")*)" autocomplete$$/
728 *
729 * @param string $option Name of option
730 * @param string $field Field name
731 */
732 public function i_should_see_in_the_list_of_option_for_the_autocomplete($option, $field) {
733 $xpathtarget = "//div[contains(@class, 'form-autocomplete-selection') and contains(.//div, '" . $option . "')]";
734 $node = $this->get_node_in_container('xpath_element', $xpathtarget, 'form_row', $field);
735 $this->ensure_node_is_visible($node);
736 }
23ebc481 737}