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 * Single select form field class. 19 * 20 * @package core_form 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__ . '/behat_form_field.php'); 29 30 /** 31 * Single select form field. 32 * 33 * @package core_form 34 * @category test 35 * @copyright 2012 David MonllaĆ³ 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class behat_form_select extends behat_form_field { 39 40 /** 41 * Sets the value(s) of a select element. 42 * 43 * Seems an easy select, but there are lots of combinations 44 * of browsers and operative systems and each one manages the 45 * autosubmits and the multiple option selects in a different way. 46 * 47 * @param string $value plain value or comma separated values if multiple. Commas in values escaped with backslash. 48 * @return void 49 */ 50 public function set_value($value) { 51 52 // Is the select multiple? 53 $multiple = $this->field->hasAttribute('multiple'); 54 55 // Here we select the option(s). 56 if ($multiple) { 57 // Split and decode values. Comma separated list of values allowed. With valuable commas escaped with backslash. 58 $options = preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', trim($value))); 59 // This is a multiple select, let's pass the multiple flag after first option. 60 $afterfirstoption = false; 61 foreach ($options as $option) { 62 $this->field->selectOption(trim($option), $afterfirstoption); 63 $afterfirstoption = true; 64 } 65 } else { 66 // By default, assume the passed value is a non-multiple option. 67 $this->field->selectOption(trim($value)); 68 } 69 } 70 71 /** 72 * Returns the text of the currently selected options. 73 * 74 * @return string Comma separated if multiple options are selected. Commas in option texts escaped with backslash. 75 */ 76 public function get_value() { 77 return $this->get_selected_options(); 78 } 79 80 /** 81 * Returns whether the provided argument matches the current value. 82 * 83 * @param mixed $expectedvalue 84 * @return bool 85 */ 86 public function matches($expectedvalue) { 87 88 $multiple = $this->field->hasAttribute('multiple'); 89 90 // Same implementation as the parent if it is a single select. 91 if (!$multiple) { 92 $cleanexpectedvalue = trim($expectedvalue); 93 $selectedtext = trim($this->get_selected_options()); 94 $selectedvalue = trim($this->get_selected_options(false)); 95 if ($cleanexpectedvalue != $selectedvalue && $cleanexpectedvalue != $selectedtext) { 96 return false; 97 } 98 return true; 99 } 100 101 // We are dealing with a multi-select. 102 103 // Unescape + trim all options and flip it to have the expected values as keys. 104 $expectedoptions = $this->get_unescaped_options($expectedvalue); 105 106 // Get currently selected option's texts. 107 $texts = $this->get_selected_options(true); 108 $selectedoptiontexts = $this->get_unescaped_options($texts); 109 110 // Get currently selected option's values. 111 $values = $this->get_selected_options(false); 112 $selectedoptionvalues = $this->get_unescaped_options($values); 113 114 // We check against string-ordered lists of options. 115 if ($expectedoptions !== $selectedoptiontexts && 116 $expectedoptions !== $selectedoptionvalues) { 117 return false; 118 } 119 120 return true; 121 } 122 123 /** 124 * Cleans the list of options and returns it as a string separating options with |||. 125 * 126 * @param string $value The string containing the escaped options. 127 * @return string The options 128 */ 129 protected function get_unescaped_options($value) { 130 131 // Can be multiple comma separated, with valuable commas escaped with backslash. 132 $optionsarray = array_map( 133 'trim', 134 preg_replace('/\\\,/', ',', 135 preg_split('/(?<!\\\),/', $value) 136 ) 137 ); 138 139 // Sort by value (keeping the keys is irrelevant). 140 core_collator::asort($optionsarray, SORT_STRING); 141 142 // Returning it as a string which is easier to match against other values. 143 return implode('|||', $optionsarray); 144 } 145 146 /** 147 * Returns the field selected values. 148 * 149 * Externalized from the common behat_form_field API method get_value() as 150 * matches() needs to check against both values and texts. 151 * 152 * @param bool $returntexts Returns the options texts or the options values. 153 * @return string 154 */ 155 protected function get_selected_options($returntexts = true) { 156 157 $method = 'getHtml'; 158 if ($returntexts === false) { 159 $method = 'getValue'; 160 } 161 162 // Is the select multiple? 163 $multiple = $this->field->hasAttribute('multiple'); 164 165 $selectedoptions = array(); // To accumulate found selected options. 166 167 // Driver returns the values as an array or as a string depending 168 // on whether multiple options are selected or not. 169 $values = $this->field->getValue(); 170 if (!is_array($values)) { 171 $values = array($values); 172 } 173 174 // Get all the options in the select and extract their value/text pairs. 175 $alloptions = $this->field->findAll('xpath', '//option'); 176 foreach ($alloptions as $option) { 177 // Is it selected? 178 if (in_array($option->getValue(), $values)) { 179 if ($multiple) { 180 // If the select is multiple, text commas must be encoded. 181 $selectedoptions[] = trim(str_replace(',', '\,', $option->{$method}())); 182 } else { 183 $selectedoptions[] = trim($option->{$method}()); 184 } 185 } 186 } 187 188 return implode(', ', $selectedoptions); 189 } 190 191 /** 192 * Returns the opton XPath based on it's select xpath. 193 * 194 * @param string $option 195 * @param string $selectxpath 196 * @return string xpath 197 */ 198 protected function get_option_xpath($option, $selectxpath) { 199 $valueliteral = behat_context_helper::escape(trim($option)); 200 return $selectxpath . "/descendant::option[(./@value=$valueliteral or normalize-space(.)=$valueliteral)]"; 201 } 202 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body