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