Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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 * Generic moodleforms field. 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 use Behat\Mink\Element\NodeElement; 29 use Behat\Mink\Session; 30 31 /** 32 * Representation of a form field. 33 * 34 * Basically an interface with Mink session. 35 * 36 * @package core_form 37 * @category test 38 * @copyright 2012 David MonllaĆ³ 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class behat_form_field implements behat_session_interface { 42 43 // All of the functionality of behat_base is shared with form fields via the behat_session_trait trait. 44 use behat_session_trait; 45 46 /** 47 * @var Session Behat session. 48 */ 49 protected $session; 50 51 /** 52 * @var NodeElement The field DOM node to interact with. 53 */ 54 protected $field; 55 56 /** 57 * @var string The field's locator. 58 */ 59 protected $fieldlocator = false; 60 61 /** 62 * Returns the Mink session. 63 * 64 * @param string|null $name name of the session OR active session will be used 65 * @return \Behat\Mink\Session 66 */ 67 public function getSession($name = null) { 68 return $this->session; 69 } 70 71 72 /** 73 * General constructor with the node and the session to interact with. 74 * 75 * @param Session $session Reference to Mink session to traverse/modify the page DOM. 76 * @param NodeElement $fieldnode The field DOM node 77 * @return void 78 */ 79 public function __construct(Session $session, NodeElement $fieldnode) { 80 $this->session = $session; 81 $this->field = $fieldnode; 82 } 83 84 /** 85 * Sets the value to a field. 86 * 87 * @param string $value 88 * @return void 89 */ 90 public function set_value($value) { 91 // We delegate to the best guess, if we arrived here 92 // using the generic behat_form_field is because we are 93 // dealing with a fgroup element. 94 $instance = $this->guess_type(); 95 return $instance->set_value($value); 96 } 97 98 /** 99 * Returns the current value of the select element. 100 * 101 * @return string 102 */ 103 public function get_value() { 104 // We delegate to the best guess, if we arrived here 105 // using the generic behat_form_field is because we are 106 // dealing with a fgroup element. 107 $instance = $this->guess_type(); 108 return $instance->get_value(); 109 } 110 111 /** 112 * Presses specific keyboard key. 113 * 114 * @param mixed $char could be either char ('b') or char-code (98) 115 * @param string $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta') 116 */ 117 public function key_press($char, $modifier = null) { 118 // We delegate to the best guess, if we arrived here 119 // using the generic behat_form_field is because we are 120 // dealing with a fgroup element. 121 $instance = $this->guess_type(); 122 $instance->field->keyDown($char, $modifier); 123 try { 124 $instance->field->keyPress($char, $modifier); 125 $instance->field->keyUp($char, $modifier); 126 } catch (\Facebook\WebDriver\Exception\WebDriverException $e) { 127 // If the JS handler attached to keydown or keypress destroys the element 128 // the later events may trigger errors because form element no longer exist 129 // or is not visible. Ignore such exceptions here. 130 } catch (\Behat\Mink\Exception\ElementNotFoundException $e) { 131 // Other Mink drivers can throw this for the same reason as above. 132 } 133 } 134 135 /** 136 * Generic match implementation 137 * 138 * Will work well with text-based fields, extension required 139 * for most of the other cases. 140 * 141 * @param string $expectedvalue 142 * @return bool The provided value matches the field value? 143 */ 144 public function matches($expectedvalue) { 145 // We delegate to the best guess, if we arrived here 146 // using the generic behat_form_field is because we are 147 // dealing with a fgroup element. 148 $instance = $this->guess_type(); 149 return $instance->matches($expectedvalue); 150 } 151 152 /** 153 * Get the value of an attribute set on this field. 154 * 155 * @param string $name The attribute name 156 * @return string The attribute value 157 */ 158 public function get_attribute($name) { 159 return $this->field->getAttribute($name); 160 } 161 162 /** 163 * Guesses the element type we are dealing with in case is not a text-based element. 164 * 165 * This class is the generic field type, behat_field_manager::get_form_field() 166 * should be able to find the appropiate class for the field type, but 167 * in cases like moodle form group elements we can not find the type of 168 * the field through the DOM so we also need to take care of the 169 * different field types from here. If we need to deal with more complex 170 * moodle form elements we will need to refactor this simple HTML elements 171 * guess method. 172 * 173 * @return behat_form_field 174 */ 175 private function guess_type() { 176 return $this->get_field_instance_for_element($this->field); 177 } 178 179 /** 180 * Returns the appropriate form field object for a given node element. 181 * 182 * @param NodeElement $element The node element 183 * @return behat_form_field 184 */ 185 protected function get_field_instance_for_element(NodeElement $element): behat_form_field { 186 global $CFG; 187 188 // We default to the text-based field if nothing was detected. 189 if (!$type = behat_field_manager::guess_field_type($element, $this->session)) { 190 $type = 'text'; 191 } 192 193 $classname = 'behat_form_' . $type; 194 $classpath = $CFG->dirroot . '/lib/behat/form_field/' . $classname . '.php'; 195 require_once($classpath); 196 197 return new $classname($this->session, $element); 198 } 199 200 /** 201 * Returns whether the scenario is running in a browser that can run Javascript or not. 202 * 203 * @return bool 204 */ 205 protected function running_javascript() { 206 return get_class($this->session->getDriver()) !== 'Behat\Mink\Driver\GoutteDriver'; 207 } 208 209 /** 210 * Waits for all the JS activity to be completed. 211 * 212 * @return bool Whether any JS is still pending completion. 213 */ 214 protected function wait_for_pending_js() { 215 if (!$this->running_javascript()) { 216 // JS is not available therefore there is nothing to wait for. 217 return false; 218 } 219 220 return behat_base::wait_for_pending_js_in_session($this->session); 221 } 222 223 /** 224 * Gets the field internal id used by selenium wire protocol. 225 * 226 * Only available when running_javascript(). 227 * 228 * @throws coding_exception 229 * @return int 230 */ 231 protected function get_internal_field_id() { 232 if (!$this->running_javascript()) { 233 throw new coding_exception('You can only get an internal ID using the selenium driver.'); 234 } 235 236 return $this->getSession() 237 ->getDriver() 238 ->getWebDriver() 239 ->findElement(WebDriverBy::xpath($node->getXpath())) 240 ->getID(); 241 } 242 243 /** 244 * Checks if the provided text matches the field value. 245 * 246 * @param string $expectedvalue 247 * @return bool 248 */ 249 protected function text_matches($expectedvalue) { 250 if (trim($expectedvalue) != trim($this->get_value())) { 251 return false; 252 } 253 return true; 254 } 255 256 /** 257 * Gets the field locator. 258 * 259 * Defaults to the field label but you can 260 * specify other locators if you are interested. 261 * 262 * Public visibility as in most cases will be hard to 263 * use this method in a generic way, as fields can 264 * be selected using multiple ways (label, id, name...). 265 * 266 * @throws coding_exception 267 * @param string $locatortype 268 * @return string 269 */ 270 protected function get_field_locator($locatortype = false) { 271 272 if (!empty($this->fieldlocator)) { 273 return $this->fieldlocator; 274 } 275 276 $fieldid = $this->field->getAttribute('id'); 277 278 // Defaults to label. 279 if ($locatortype == 'label' || $locatortype == false) { 280 281 $labelnode = $this->session->getPage()->find('xpath', "//label[@for='$fieldid']|//p[@id='{$fieldid}_label']"); 282 283 // Exception only if $locatortype was specified. 284 if (!$labelnode && $locatortype == 'label') { 285 throw new coding_exception('Field with "' . $fieldid . '" id does not have a label.'); 286 } 287 288 $this->fieldlocator = $labelnode->getText(); 289 } 290 291 // Let's look for the name as a second option (more popular than 292 // id's when pointing to fields). 293 if (($locatortype == 'name' || $locatortype == false) && 294 empty($this->fieldlocator)) { 295 296 $name = $this->field->getAttribute('name'); 297 298 // Exception only if $locatortype was specified. 299 if (!$name && $locatortype == 'name') { 300 throw new coding_exception('Field with "' . $fieldid . '" id does not have a name attribute.'); 301 } 302 303 $this->fieldlocator = $name; 304 } 305 306 // Otherwise returns the id if no specific locator type was provided. 307 if (empty($this->fieldlocator)) { 308 $this->fieldlocator = $fieldid; 309 } 310 311 return $this->fieldlocator; 312 } 313 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body