See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 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 * Moodle-specific selectors. 19 * 20 * @package core 21 * @category test 22 * @copyright 2013 David MonllaĆ³ 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 /** 27 * Moodle selectors manager. 28 * 29 * @package core 30 * @category test 31 * @copyright 2013 David MonllaĆ³ 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class behat_partial_named_selector extends \Behat\Mink\Selector\PartialNamedSelector { 35 36 // Use the named selector trait. 37 use behat_named_selector; 38 39 /** 40 * Creates selector instance. 41 */ 42 public function __construct() { 43 foreach (self::$customselectors as $alias => $selectors) { 44 $this->registerNamedXpath($alias, implode(' | ', $selectors)); 45 } 46 47 foreach (static::$moodleselectors as $name => $xpath) { 48 $this->registerNamedXpath($name, $xpath); 49 } 50 51 foreach (self::$customreplacements as $from => $tos) { 52 $this->registerReplacement($from, implode(' or ', $tos)); 53 } 54 55 $this->registerReplacement('%iconMatch%', "(contains(concat(' ', @class, ' '), ' icon ') or self::img)"); 56 $this->registerReplacement('%imgAltMatch%', './/*[%iconMatch% and (%altMatch% or %titleMatch%)]'); 57 parent::__construct(); 58 } 59 60 /** 61 * @var array Allowed types when using text selectors arguments. 62 */ 63 protected static $allowedtextselectors = array( 64 'activity' => 'activity', 65 'block' => 'block', 66 'css_element' => 'css_element', 67 'dialogue' => 'dialogue', 68 'fieldset' => 'fieldset', 69 'icon' => 'icon', 70 'list_item' => 'list_item', 71 'question' => 'question', 72 'region' => 'region', 73 'section' => 'section', 74 'table' => 'table', 75 'table_row' => 'table_row', 76 'xpath_element' => 'xpath_element', 77 'form_row' => 'form_row', 78 'group_message_header' => 'group_message_header', 79 'group_message' => 'group_message', 80 'autocomplete' => 'autocomplete', 81 'iframe' => 'iframe', 82 ); 83 84 /** 85 * @var array Allowed types when using selector arguments. 86 */ 87 protected static $allowedselectors = array( 88 'activity' => 'activity', 89 'actionmenu' => 'actionmenu', 90 'badge' => 'badge', 91 'block' => 'block', 92 'button' => 'button', 93 'checkbox' => 'checkbox', 94 'css_element' => 'css_element', 95 'dialogue' => 'dialogue', 96 'field' => 'field', 97 'fieldset' => 'fieldset', 98 'file' => 'file', 99 'filemanager' => 'filemanager', 100 'group_message' => 'group_message', 101 'group_message_conversation' => 'group_message_conversation', 102 'group_message_header' => 'group_message_header', 103 'group_message_member' => 'group_message_member', 104 'group_message_tab' => 'group_message_tab', 105 'group_message_list_area' => 'group_message_list_area', 106 'group_message_message_content' => 'group_message_message_content', 107 'icon_container' => 'icon_container', 108 'icon' => 'icon', 109 'link' => 'link', 110 'link_or_button' => 'link_or_button', 111 'list_item' => 'list_item', 112 'menuitem' => 'menuitem', 113 'optgroup' => 'optgroup', 114 'option' => 'option', 115 'question' => 'question', 116 'radio' => 'radio', 117 'region' => 'region', 118 'section' => 'section', 119 'select' => 'select', 120 'table' => 'table', 121 'table_row' => 'table_row', 122 'text' => 'text', 123 'xpath_element' => 'xpath_element', 124 'form_row' => 'form_row', 125 'autocomplete_selection' => 'autocomplete_selection', 126 'autocomplete_suggestions' => 'autocomplete_suggestions', 127 'autocomplete' => 'autocomplete', 128 'iframe' => 'iframe', 129 ); 130 131 /** 132 * Behat by default comes with XPath, CSS and named selectors, 133 * named selectors are a mapping between names (like button) and 134 * xpaths that represents that names and includes a placeholder that 135 * will be replaced by the locator. These are Moodle's own xpaths. 136 * 137 * @var array XPaths for moodle elements. 138 */ 139 protected static $moodleselectors = array( 140 'activity' => <<<XPATH 141 .//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][descendant::*[contains(normalize-space(.), %locator%)]] 142 XPATH 143 , 'actionmenu' => <<<XPATH 144 .//*[ 145 contains(concat(' ', normalize-space(@class), ' '), ' action-menu ') 146 and 147 descendant::*[ 148 contains(concat(' ', normalize-space(@class), ' '), ' dropdown-toggle ') 149 and 150 (contains(normalize-space(.), %locator%) or descendant::*[%titleMatch%]) 151 ] 152 ] 153 XPATH 154 , 'badge' => <<<XPATH 155 .//span[(contains(@class, 'badge')) and text()[contains(., %locator%)]] 156 XPATH 157 , 'block' => <<<XPATH 158 .//*[@data-block][contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or 159 descendant::*[self::h2|self::h3|self::h4|self::h5][normalize-space(.) = %locator%] or 160 @aria-label = %locator%] 161 XPATH 162 , 'dialogue' => <<<XPATH 163 .//div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue ') and 164 not(contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-hidden ')) and 165 normalize-space(descendant::div[ 166 contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-hd ') 167 ]) = %locator%] | 168 .//div[contains(concat(' ', normalize-space(@class), ' '), ' yui-dialog ') and 169 normalize-space(descendant::div[@class='hd']) = %locator%] 170 | 171 .//div[@data-region='modal' and descendant::*[@data-region='title'] = %locator%] 172 | 173 .//div[ 174 contains(concat(' ', normalize-space(@class), ' '), ' modal-content ') 175 and 176 normalize-space(descendant::*[self::h4 or self::h5][contains(concat(' ', normalize-space(@class), ' '), ' modal-title ')]) = %locator% 177 ] 178 | 179 .//div[ 180 contains(concat(' ', normalize-space(@class), ' '), ' modal ') 181 and 182 normalize-space(descendant::*[contains(concat(' ', normalize-space(@class), ' '), ' modal-header ')]) = %locator% 183 ] 184 XPATH 185 , 'group_message' => <<<XPATH 186 .//*[@data-conversation-id]//img[contains(@alt, %locator%)]/.. 187 XPATH 188 , 'group_message_conversation' => <<<XPATH 189 .//*[@data-region='message-drawer' and contains(., %locator%)]//div[@data-region='content-message-container'] 190 XPATH 191 , 'group_message_header' => <<<XPATH 192 .//*[@data-region='message-drawer']//div[@data-region='header-content' and contains(., %locator%)] 193 XPATH 194 , 'group_message_member' => <<<XPATH 195 .//*[@data-region='message-drawer']//div[@data-region='group-info-content-container'] 196 //div[@class='list-group' and not(contains(@class, 'hidden'))]//*[text()[contains(., %locator%)]] | 197 .//*[@data-region='message-drawer']//div[@data-region='group-info-content-container'] 198 //div[@data-region='empty-message-container' and not(contains(@class, 'hidden')) and contains(., %locator%)] 199 XPATH 200 , 'group_message_tab' => <<<XPATH 201 .//*[@data-region='message-drawer']//button[@data-toggle='collapse' and contains(string(), %locator%)] 202 XPATH 203 , 'group_message_list_area' => <<<XPATH 204 .//*[@data-region='message-drawer']//*[contains(@data-region, concat('view-overview-', %locator%))] 205 XPATH 206 , 'group_message_message_content' => <<<XPATH 207 .//*[@data-region='message-drawer']//*[@data-region='message' and @data-message-id and contains(., %locator%)] 208 XPATH 209 , 'icon_container' => <<<XPATH 210 .//span[contains(@data-region, concat(%locator%,'-icon-container'))] 211 XPATH 212 , 'icon' => <<<XPATH 213 .//*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') and ( contains(normalize-space(@title), %locator%))] 214 XPATH 215 , 'list_item' => <<<XPATH 216 .//li[contains(normalize-space(.), %locator%) and not(.//li[contains(normalize-space(.), %locator%)])] 217 XPATH 218 , 'menuitem' => <<<XPATH 219 .//*[@role='menuitem'][%titleMatch% or %ariaLabelMatch% or text()[contains(., %locator%)]] 220 XPATH 221 , 'question' => <<<XPATH 222 .//div[contains(concat(' ', normalize-space(@class), ' '), ' que ')] 223 [contains(div[@class='content']/div[contains(concat(' ', normalize-space(@class), ' '), ' formulation ')], %locator%)] 224 XPATH 225 , 'region' => <<<XPATH 226 .//*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%] 227 XPATH 228 , 'section' => <<<XPATH 229 .//li[contains(concat(' ', normalize-space(@class), ' '), ' section ')][./descendant::*[self::h3] 230 [normalize-space(.) = %locator%][contains(concat(' ', normalize-space(@class), ' '), ' sectionname ') or 231 contains(concat(' ', normalize-space(@class), ' '), ' section-title ')]] | 232 .//div[contains(concat(' ', normalize-space(@class), ' '), ' sitetopic ')] 233 [./descendant::*[self::h2][normalize-space(.) = %locator%] or %locator% = 'frontpage'] 234 XPATH 235 , 'table' => <<<XPATH 236 .//table[(./@id = %locator% or contains(.//caption, %locator%) or contains(.//th, %locator%) or contains(concat(' ', normalize-space(@class), ' '), %locator% ))] 237 XPATH 238 , 'table_row' => <<<XPATH 239 .//tr[contains(normalize-space(.), %locator%) and not(.//tr[contains(normalize-space(.), %locator%)])] 240 XPATH 241 , 'text' => <<<XPATH 242 .//*[contains(., %locator%) and not(.//*[contains(., %locator%)])] 243 XPATH 244 , 'form_row' => <<<XPATH 245 .//*[contains(concat(' ', @class, ' '), ' col-form-label ')] 246 [normalize-space(.)= %locator%] 247 /ancestor::*[contains(concat(' ', @class, ' '), ' fitem ')] 248 XPATH 249 , 'autocomplete_selection' => <<<XPATH 250 .//div[contains(concat(' ', normalize-space(@class), ' '), concat(' ', 'form-autocomplete-selection', ' '))]/span[@role='option'][contains(normalize-space(.), %locator%)] 251 XPATH 252 , 'autocomplete_suggestions' => <<<XPATH 253 .//ul[contains(concat(' ', normalize-space(@class), ' '), concat(' ', 'form-autocomplete-suggestions', ' '))]/li[@role='option'][contains(normalize-space(.), %locator%)] 254 XPATH 255 , 'autocomplete' => <<<XPATH 256 .//descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]/ancestor::*[@data-fieldtype = 'autocomplete'] 257 XPATH 258 , 'iframe' => <<<XPATH 259 .//iframe[(%idOrNameMatch% or (contains(concat(' ', normalize-space(@class), ' '), %locator% )))] 260 XPATH 261 ); 262 263 protected static $customselectors = [ 264 'field' => [ 265 'upstream' => <<<XPATH 266 .//* 267 [%fieldFilterWithPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithPlaceholder%] 268 | 269 .//label[%tagTextMatch%]//.//*[%fieldFilterWithPlaceholder%][%notFieldTypeFilter%] 270 | 271 .//* 272 [%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithoutPlaceholder%] 273 | 274 .//label[%tagTextMatch%]//.//*[%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%] 275 XPATH 276 , 277 'filemanager' => <<<XPATH 278 .//*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker'] 279 /descendant::input[@id = substring-before(//p[contains(normalize-space(string(.)), %locator%)]/@id, '_label')] 280 XPATH 281 , 282 'passwordunmask' => <<<XPATH 283 .//*[@data-passwordunmask='wrapper'] 284 /descendant::input[@id = %locator% or @id = //label[contains(normalize-space(string(.)), %locator%)]/@for] 285 XPATH 286 , 287 'inplaceeditable' => <<<XPATH 288 .//descendant::span[@data-inplaceeditable][descendant::a[%titleMatch%]] 289 XPATH 290 , 291 'date_time' => <<<XPATH 292 .//fieldset[(%idMatch% or ./legend[%exactTagTextMatch%]) and (@data-fieldtype='date' or @data-fieldtype='date_time')] 293 XPATH 294 , 295 'select_menu' => <<<XPATH 296 //*[@role='combobox'][@aria-labelledby = //label[contains(normalize-space(string(.)), %locator%)]/@id] 297 XPATH 298 , 299 ], 300 ]; 301 302 /** 303 * Mink comes with a number of named replacements. 304 * Sometimes we want to add our own. 305 * 306 * @var array XPaths for moodle elements. 307 */ 308 protected static $customreplacements = [ 309 '%buttonMatch%' => [ 310 'upstream' => '%idOrNameMatch% or %valueMatch% or %titleMatch%', 311 'aria' => '%ariaLabelMatch%', 312 ], 313 '%ariaLabelMatch%' => [ 314 'moodle' => 'contains(./@aria-label, %locator%)', 315 ], 316 '%exactTagTextMatch%' => [ 317 // This is based upon the upstream tagTextMatch but performs an exact match rather than a loose match using 318 // contains(). 319 // If possible we should only use exact matches for any new form fields that we add. 320 'moodle' => 'normalize-space(text())=%locator%', 321 ], 322 ]; 323 324 /** @var List of deprecated selectors */ 325 protected static $deprecatedselectors = [ 326 'group_message' => 'core_message > Message', 327 'group_message_member' => 'core_message > Message member', 328 'group_message_tab' => 'core_message > Message tab', 329 'group_message_list_area' => 'core_message > Message list area', 330 'group_message_message_content' => 'core_message > Message content', 331 ]; 332 333 /** 334 * Allowed selectors getter. 335 * 336 * @return array 337 */ 338 public static function get_allowed_selectors() { 339 return static::$allowedselectors; 340 } 341 342 /** 343 * Allowed text selectors getter. 344 * 345 * @return array 346 */ 347 public static function get_allowed_text_selectors() { 348 return static::$allowedtextselectors; 349 } 350 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body