See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 'block' => 'block', 91 'button' => 'button', 92 'checkbox' => 'checkbox', 93 'css_element' => 'css_element', 94 'dialogue' => 'dialogue', 95 'field' => 'field', 96 'fieldset' => 'fieldset', 97 'file' => 'file', 98 'filemanager' => 'filemanager', 99 'group_message' => 'group_message', 100 'group_message_conversation' => 'group_message_conversation', 101 'group_message_header' => 'group_message_header', 102 'group_message_member' => 'group_message_member', 103 'group_message_tab' => 'group_message_tab', 104 'group_message_list_area' => 'group_message_list_area', 105 'group_message_message_content' => 'group_message_message_content', 106 'icon_container' => 'icon_container', 107 'icon' => 'icon', 108 'link' => 'link', 109 'link_or_button' => 'link_or_button', 110 'list_item' => 'list_item', 111 'optgroup' => 'optgroup', 112 'option' => 'option', 113 'question' => 'question', 114 'radio' => 'radio', 115 'region' => 'region', 116 'section' => 'section', 117 'select' => 'select', 118 'table' => 'table', 119 'table_row' => 'table_row', 120 'text' => 'text', 121 'xpath_element' => 'xpath_element', 122 'form_row' => 'form_row', 123 'autocomplete_selection' => 'autocomplete_selection', 124 'autocomplete_suggestions' => 'autocomplete_suggestions', 125 'autocomplete' => 'autocomplete', 126 'iframe' => 'iframe', 127 ); 128 129 /** 130 * Behat by default comes with XPath, CSS and named selectors, 131 * named selectors are a mapping between names (like button) and 132 * xpaths that represents that names and includes a placeholder that 133 * will be replaced by the locator. These are Moodle's own xpaths. 134 * 135 * @var array XPaths for moodle elements. 136 */ 137 protected static $moodleselectors = array( 138 'activity' => <<<XPATH 139 .//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][descendant::*[contains(normalize-space(.), %locator%)]] 140 XPATH 141 , 'actionmenu' => <<<XPATH 142 .//*[ 143 contains(concat(' ', normalize-space(@class), ' '), ' action-menu ') 144 and 145 descendant::*[ 146 contains(concat(' ', normalize-space(@class), ' '), ' dropdown-toggle ') 147 and 148 (contains(normalize-space(.), %locator%) or descendant::*[%titleMatch%]) 149 ] 150 ] 151 XPATH 152 , 'block' => <<<XPATH 153 .//*[@data-block][contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or 154 descendant::*[self::h2|self::h3|self::h4|self::h5][normalize-space(.) = %locator%] or 155 @aria-label = %locator%] 156 XPATH 157 , 'dialogue' => <<<XPATH 158 .//div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue ') and 159 normalize-space(descendant::div[ 160 contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-hd ') 161 ]) = %locator%] | 162 .//div[contains(concat(' ', normalize-space(@class), ' '), ' yui-dialog ') and 163 normalize-space(descendant::div[@class='hd']) = %locator%] 164 | 165 .//div[@data-region='modal' and descendant::*[@data-region='title'] = %locator%] 166 | 167 .//div[ 168 contains(concat(' ', normalize-space(@class), ' '), ' modal-content ') 169 and 170 normalize-space(descendant::*[self::h4 or self::h5][contains(concat(' ', normalize-space(@class), ' '), ' modal-title ')]) = %locator% 171 ] 172 | 173 .//div[ 174 contains(concat(' ', normalize-space(@class), ' '), ' modal ') 175 and 176 normalize-space(descendant::*[contains(concat(' ', normalize-space(@class), ' '), ' modal-header ')]) = %locator% 177 ] 178 XPATH 179 , 'group_message' => <<<XPATH 180 .//*[@data-conversation-id]//img[contains(@alt, %locator%)]/.. 181 XPATH 182 , 'group_message_conversation' => <<<XPATH 183 .//*[@data-region='message-drawer' and contains(., %locator%)]//div[@data-region='content-message-container'] 184 XPATH 185 , 'group_message_header' => <<<XPATH 186 .//*[@data-region='message-drawer']//div[@data-region='header-content' and contains(., %locator%)] 187 XPATH 188 , 'group_message_member' => <<<XPATH 189 .//*[@data-region='message-drawer']//div[@data-region='group-info-content-container'] 190 //div[@class='list-group' and not(contains(@class, 'hidden'))]//*[text()[contains(., %locator%)]] | 191 .//*[@data-region='message-drawer']//div[@data-region='group-info-content-container'] 192 //div[@data-region='empty-message-container' and not(contains(@class, 'hidden')) and contains(., %locator%)] 193 XPATH 194 , 'group_message_tab' => <<<XPATH 195 .//*[@data-region='message-drawer']//button[@data-toggle='collapse' and contains(string(), %locator%)] 196 XPATH 197 , 'group_message_list_area' => <<<XPATH 198 .//*[@data-region='message-drawer']//*[contains(@data-region, concat('view-overview-', %locator%))] 199 XPATH 200 , 'group_message_message_content' => <<<XPATH 201 .//*[@data-region='message-drawer']//*[@data-region='message' and @data-message-id and contains(., %locator%)] 202 XPATH 203 , 'icon_container' => <<<XPATH 204 .//span[contains(@data-region, concat(%locator%,'-icon-container'))] 205 XPATH 206 , 'icon' => <<<XPATH 207 .//*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') and ( contains(normalize-space(@title), %locator%))] 208 XPATH 209 , 'list_item' => <<<XPATH 210 .//li[contains(normalize-space(.), %locator%) and not(.//li[contains(normalize-space(.), %locator%)])] 211 XPATH 212 , 'question' => <<<XPATH 213 .//div[contains(concat(' ', normalize-space(@class), ' '), ' que ')] 214 [contains(div[@class='content']/div[contains(concat(' ', normalize-space(@class), ' '), ' formulation ')], %locator%)] 215 XPATH 216 , 'region' => <<<XPATH 217 .//*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%] 218 XPATH 219 , 'section' => <<<XPATH 220 .//li[contains(concat(' ', normalize-space(@class), ' '), ' section ')][./descendant::*[self::h3] 221 [normalize-space(.) = %locator%][contains(concat(' ', normalize-space(@class), ' '), ' sectionname ') or 222 contains(concat(' ', normalize-space(@class), ' '), ' section-title ')]] | 223 .//div[contains(concat(' ', normalize-space(@class), ' '), ' sitetopic ')] 224 [./descendant::*[self::h2][normalize-space(.) = %locator%] or %locator% = 'frontpage'] 225 XPATH 226 , 'table' => <<<XPATH 227 .//table[(./@id = %locator% or contains(.//caption, %locator%) or contains(.//th, %locator%) or contains(concat(' ', normalize-space(@class), ' '), %locator% ))] 228 XPATH 229 , 'table_row' => <<<XPATH 230 .//tr[contains(normalize-space(.), %locator%) and not(.//tr[contains(normalize-space(.), %locator%)])] 231 XPATH 232 , 'text' => <<<XPATH 233 .//*[contains(., %locator%) and not(.//*[contains(., %locator%)])] 234 XPATH 235 , 'form_row' => <<<XPATH 236 .//*[contains(concat(' ', @class, ' '), ' col-form-label ')] 237 [normalize-space(.)= %locator%] 238 /ancestor::*[contains(concat(' ', @class, ' '), ' fitem ')] 239 XPATH 240 , 'autocomplete_selection' => <<<XPATH 241 .//div[contains(concat(' ', normalize-space(@class), ' '), concat(' ', 'form-autocomplete-selection', ' '))]/span[@role='option'][contains(normalize-space(.), %locator%)] 242 XPATH 243 , 'autocomplete_suggestions' => <<<XPATH 244 .//ul[contains(concat(' ', normalize-space(@class), ' '), concat(' ', 'form-autocomplete-suggestions', ' '))]/li[@role='option'][contains(normalize-space(.), %locator%)] 245 XPATH 246 , 'autocomplete' => <<<XPATH 247 .//descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]/ancestor::*[@data-fieldtype = 'autocomplete'] 248 XPATH 249 , 'iframe' => <<<XPATH 250 .//iframe[(%idOrNameMatch% or (contains(concat(' ', normalize-space(@class), ' '), %locator% )))] 251 XPATH 252 ); 253 254 protected static $customselectors = [ 255 'field' => [ 256 'upstream' => <<<XPATH 257 .//* 258 [%fieldFilterWithPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithPlaceholder%] 259 | 260 .//label[%tagTextMatch%]//.//*[%fieldFilterWithPlaceholder%][%notFieldTypeFilter%] 261 | 262 .//* 263 [%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithoutPlaceholder%] 264 | 265 .//label[%tagTextMatch%]//.//*[%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%] 266 XPATH 267 , 268 'filemanager' => <<<XPATH 269 .//*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker'] 270 /descendant::input[@id = substring-before(//p[contains(normalize-space(string(.)), %locator%)]/@id, '_label')] 271 XPATH 272 , 273 'passwordunmask' => <<<XPATH 274 .//*[@data-passwordunmask='wrapper'] 275 /descendant::input[@id = %locator% or @id = //label[contains(normalize-space(string(.)), %locator%)]/@for] 276 XPATH 277 , 278 'inplaceeditable' => <<<XPATH 279 .//descendant::span[@data-inplaceeditable][descendant::a[%titleMatch%]] 280 XPATH 281 , 282 'date_time' => <<<XPATH 283 .//fieldset[(%idMatch% or ./legend[%exactTagTextMatch%]) and (@data-fieldtype='date' or @data-fieldtype='date_time')] 284 XPATH 285 ], 286 ]; 287 288 /** 289 * Mink comes with a number of named replacements. 290 * Sometimes we want to add our own. 291 * 292 * @var array XPaths for moodle elements. 293 */ 294 protected static $customreplacements = [ 295 '%buttonMatch%' => [ 296 'upstream' => '%idOrNameMatch% or %valueMatch% or %titleMatch%', 297 'aria' => '%ariaLabelMatch%', 298 ], 299 '%ariaLabelMatch%' => [ 300 'moodle' => 'contains(./@aria-label, %locator%)', 301 ], 302 '%exactTagTextMatch%' => [ 303 // This is based upon the upstream tagTextMatch but performs an exact match rather than a loose match using 304 // contains(). 305 // If possible we should only use exact matches for any new form fields that we add. 306 'moodle' => 'normalize-space(text())=%locator%', 307 ], 308 ]; 309 310 /** @var List of deprecated selectors */ 311 protected static $deprecatedselectors = [ 312 'group_message' => 'core_message > Message', 313 'group_message_member' => 'core_message > Message member', 314 'group_message_tab' => 'core_message > Message tab', 315 'group_message_list_area' => 'core_message > Message list area', 316 'group_message_message_content' => 'core_message > Message content', 317 ]; 318 319 /** 320 * Allowed selectors getter. 321 * 322 * @return array 323 */ 324 public static function get_allowed_selectors() { 325 return static::$allowedselectors; 326 } 327 328 /** 329 * Allowed text selectors getter. 330 * 331 * @return array 332 */ 333 public static function get_allowed_text_selectors() { 334 return static::$allowedtextselectors; 335 } 336 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body