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