Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 not(contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-hidden ')) and 160 normalize-space(descendant::div[ 161 contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-hd ') 162 ]) = %locator%] | 163 .//div[contains(concat(' ', normalize-space(@class), ' '), ' yui-dialog ') and 164 normalize-space(descendant::div[@class='hd']) = %locator%] 165 | 166 .//div[@data-region='modal' and descendant::*[@data-region='title'] = %locator%] 167 | 168 .//div[ 169 contains(concat(' ', normalize-space(@class), ' '), ' modal-content ') 170 and 171 normalize-space(descendant::*[self::h4 or self::h5][contains(concat(' ', normalize-space(@class), ' '), ' modal-title ')]) = %locator% 172 ] 173 | 174 .//div[ 175 contains(concat(' ', normalize-space(@class), ' '), ' modal ') 176 and 177 normalize-space(descendant::*[contains(concat(' ', normalize-space(@class), ' '), ' modal-header ')]) = %locator% 178 ] 179 XPATH 180 , 'group_message' => <<<XPATH 181 .//*[@data-conversation-id]//img[contains(@alt, %locator%)]/.. 182 XPATH 183 , 'group_message_conversation' => <<<XPATH 184 .//*[@data-region='message-drawer' and contains(., %locator%)]//div[@data-region='content-message-container'] 185 XPATH 186 , 'group_message_header' => <<<XPATH 187 .//*[@data-region='message-drawer']//div[@data-region='header-content' and contains(., %locator%)] 188 XPATH 189 , 'group_message_member' => <<<XPATH 190 .//*[@data-region='message-drawer']//div[@data-region='group-info-content-container'] 191 //div[@class='list-group' and not(contains(@class, 'hidden'))]//*[text()[contains(., %locator%)]] | 192 .//*[@data-region='message-drawer']//div[@data-region='group-info-content-container'] 193 //div[@data-region='empty-message-container' and not(contains(@class, 'hidden')) and contains(., %locator%)] 194 XPATH 195 , 'group_message_tab' => <<<XPATH 196 .//*[@data-region='message-drawer']//button[@data-toggle='collapse' and contains(string(), %locator%)] 197 XPATH 198 , 'group_message_list_area' => <<<XPATH 199 .//*[@data-region='message-drawer']//*[contains(@data-region, concat('view-overview-', %locator%))] 200 XPATH 201 , 'group_message_message_content' => <<<XPATH 202 .//*[@data-region='message-drawer']//*[@data-region='message' and @data-message-id and contains(., %locator%)] 203 XPATH 204 , 'icon_container' => <<<XPATH 205 .//span[contains(@data-region, concat(%locator%,'-icon-container'))] 206 XPATH 207 , 'icon' => <<<XPATH 208 .//*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') and ( contains(normalize-space(@title), %locator%))] 209 XPATH 210 , 'list_item' => <<<XPATH 211 .//li[contains(normalize-space(.), %locator%) and not(.//li[contains(normalize-space(.), %locator%)])] 212 XPATH 213 , 'question' => <<<XPATH 214 .//div[contains(concat(' ', normalize-space(@class), ' '), ' que ')] 215 [contains(div[@class='content']/div[contains(concat(' ', normalize-space(@class), ' '), ' formulation ')], %locator%)] 216 XPATH 217 , 'region' => <<<XPATH 218 .//*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%] 219 XPATH 220 , 'section' => <<<XPATH 221 .//li[contains(concat(' ', normalize-space(@class), ' '), ' section ')][./descendant::*[self::h3] 222 [normalize-space(.) = %locator%][contains(concat(' ', normalize-space(@class), ' '), ' sectionname ') or 223 contains(concat(' ', normalize-space(@class), ' '), ' section-title ')]] | 224 .//div[contains(concat(' ', normalize-space(@class), ' '), ' sitetopic ')] 225 [./descendant::*[self::h2][normalize-space(.) = %locator%] or %locator% = 'frontpage'] 226 XPATH 227 , 'table' => <<<XPATH 228 .//table[(./@id = %locator% or contains(.//caption, %locator%) or contains(.//th, %locator%) or contains(concat(' ', normalize-space(@class), ' '), %locator% ))] 229 XPATH 230 , 'table_row' => <<<XPATH 231 .//tr[contains(normalize-space(.), %locator%) and not(.//tr[contains(normalize-space(.), %locator%)])] 232 XPATH 233 , 'text' => <<<XPATH 234 .//*[contains(., %locator%) and not(.//*[contains(., %locator%)])] 235 XPATH 236 , 'form_row' => <<<XPATH 237 .//*[contains(concat(' ', @class, ' '), ' col-form-label ')] 238 [normalize-space(.)= %locator%] 239 /ancestor::*[contains(concat(' ', @class, ' '), ' fitem ')] 240 XPATH 241 , 'autocomplete_selection' => <<<XPATH 242 .//div[contains(concat(' ', normalize-space(@class), ' '), concat(' ', 'form-autocomplete-selection', ' '))]/span[@role='option'][contains(normalize-space(.), %locator%)] 243 XPATH 244 , 'autocomplete_suggestions' => <<<XPATH 245 .//ul[contains(concat(' ', normalize-space(@class), ' '), concat(' ', 'form-autocomplete-suggestions', ' '))]/li[@role='option'][contains(normalize-space(.), %locator%)] 246 XPATH 247 , 'autocomplete' => <<<XPATH 248 .//descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]/ancestor::*[@data-fieldtype = 'autocomplete'] 249 XPATH 250 , 'iframe' => <<<XPATH 251 .//iframe[(%idOrNameMatch% or (contains(concat(' ', normalize-space(@class), ' '), %locator% )))] 252 XPATH 253 ); 254 255 protected static $customselectors = [ 256 'field' => [ 257 'upstream' => <<<XPATH 258 .//* 259 [%fieldFilterWithPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithPlaceholder%] 260 | 261 .//label[%tagTextMatch%]//.//*[%fieldFilterWithPlaceholder%][%notFieldTypeFilter%] 262 | 263 .//* 264 [%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithoutPlaceholder%] 265 | 266 .//label[%tagTextMatch%]//.//*[%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%] 267 XPATH 268 , 269 'filemanager' => <<<XPATH 270 .//*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker'] 271 /descendant::input[@id = substring-before(//p[contains(normalize-space(string(.)), %locator%)]/@id, '_label')] 272 XPATH 273 , 274 'passwordunmask' => <<<XPATH 275 .//*[@data-passwordunmask='wrapper'] 276 /descendant::input[@id = %locator% or @id = //label[contains(normalize-space(string(.)), %locator%)]/@for] 277 XPATH 278 , 279 'inplaceeditable' => <<<XPATH 280 .//descendant::span[@data-inplaceeditable][descendant::a[%titleMatch%]] 281 XPATH 282 , 283 'date_time' => <<<XPATH 284 .//fieldset[(%idMatch% or ./legend[%exactTagTextMatch%]) and (@data-fieldtype='date' or @data-fieldtype='date_time')] 285 XPATH 286 ], 287 ]; 288 289 /** 290 * Mink comes with a number of named replacements. 291 * Sometimes we want to add our own. 292 * 293 * @var array XPaths for moodle elements. 294 */ 295 protected static $customreplacements = [ 296 '%buttonMatch%' => [ 297 'upstream' => '%idOrNameMatch% or %valueMatch% or %titleMatch%', 298 'aria' => '%ariaLabelMatch%', 299 ], 300 '%ariaLabelMatch%' => [ 301 'moodle' => 'contains(./@aria-label, %locator%)', 302 ], 303 '%exactTagTextMatch%' => [ 304 // This is based upon the upstream tagTextMatch but performs an exact match rather than a loose match using 305 // contains(). 306 // If possible we should only use exact matches for any new form fields that we add. 307 'moodle' => 'normalize-space(text())=%locator%', 308 ], 309 ]; 310 311 /** @var List of deprecated selectors */ 312 protected static $deprecatedselectors = [ 313 'group_message' => 'core_message > Message', 314 'group_message_member' => 'core_message > Message member', 315 'group_message_tab' => 'core_message > Message tab', 316 'group_message_list_area' => 'core_message > Message list area', 317 'group_message_message_content' => 'core_message > Message content', 318 ]; 319 320 /** 321 * Allowed selectors getter. 322 * 323 * @return array 324 */ 325 public static function get_allowed_selectors() { 326 return static::$allowedselectors; 327 } 328 329 /** 330 * Allowed text selectors getter. 331 * 332 * @return array 333 */ 334 public static function get_allowed_text_selectors() { 335 return static::$allowedtextselectors; 336 } 337 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body