MDL-59883 behat: Check aria-label for button content
[moodle.git] / lib / behat / classes / partial_named_selector.php
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/>.
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  */
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 {
36     /**
37      * Creates selector instance.
38      */
39     public function __construct() {
40         foreach (self::$customselectors as $alias => $selectors) {
41             $this->registerNamedXpath($alias, implode(' | ', $selectors));
42         }
44         foreach (static::$moodleselectors as $name => $xpath) {
45             $this->registerNamedXpath($name, $xpath);
46         }
48         foreach (self::$customreplacements as $from => $tos) {
49             $this->registerReplacement($from, implode(' or ', $tos));
50         }
52         $this->registerReplacement('%iconMatch%', "(contains(concat(' ', @class, ' '), ' icon ') or name() = 'img')");
53         $this->registerReplacement('%imgAltMatch%', './/*[%iconMatch% and (%altMatch% or %titleMatch%)]');
54         parent::__construct();
55     }
57     /**
58      * @var array Allowed types when using text selectors arguments.
59      */
60     protected static $allowedtextselectors = array(
61         'activity' => 'activity',
62         'block' => 'block',
63         'css_element' => 'css_element',
64         'dialogue' => 'dialogue',
65         'fieldset' => 'fieldset',
66         'icon' => 'icon',
67         'list_item' => 'list_item',
68         'message_area_region' => 'message_area_region',
69         'message_area_region_content' => 'message_area_region_content',
70         'question' => 'question',
71         'region' => 'region',
72         'section' => 'section',
73         'table' => 'table',
74         'table_row' => 'table_row',
75         'xpath_element' => 'xpath_element',
76         'form_row' => 'form_row',
77     );
79     /**
80      * @var array Allowed types when using selector arguments.
81      */
82     protected static $allowedselectors = array(
83         'activity' => 'activity',
84         'block' => 'block',
85         'button' => 'button',
86         'checkbox' => 'checkbox',
87         'css_element' => 'css_element',
88         'dialogue' => 'dialogue',
89         'field' => 'field',
90         'fieldset' => 'fieldset',
91         'file' => 'file',
92         'filemanager' => 'filemanager',
93         'icon' => 'icon',
94         'link' => 'link',
95         'link_or_button' => 'link_or_button',
96         'list_item' => 'list_item',
97         'message_area_action' => 'message_area_action',
98         'message_area_region' => 'message_area_region',
99         'message_area_region_content' => 'message_area_region_content',
100         'optgroup' => 'optgroup',
101         'option' => 'option',
102         'question' => 'question',
103         'radio' => 'radio',
104         'region' => 'region',
105         'section' => 'section',
106         'select' => 'select',
107         'table' => 'table',
108         'table_row' => 'table_row',
109         'text' => 'text',
110         'xpath_element' => 'xpath_element',
111         'form_row' => 'form_row',
112     );
114     /**
115      * Behat by default comes with XPath, CSS and named selectors,
116      * named selectors are a mapping between names (like button) and
117      * xpaths that represents that names and includes a placeholder that
118      * will be replaced by the locator. These are Moodle's own xpaths.
119      *
120      * @var array XPaths for moodle elements.
121      */
122     protected static $moodleselectors = array(
123         'activity' => <<<XPATH
124 .//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][normalize-space(.) = %locator% ]
125 XPATH
126         , 'block' => <<<XPATH
127 .//*[@data-block][contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or
128      descendant::*[self::h2|self::h3][normalize-space(.) = %locator%]  or
129      @aria-label = %locator%]
130 XPATH
131         , 'dialogue' => <<<XPATH
132 .//div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue ') and
133     normalize-space(descendant::div[
134         contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue-hd ')
135         ]) = %locator%] |
136 .//div[contains(concat(' ', normalize-space(@class), ' '), ' yui-dialog ') and
137     normalize-space(descendant::div[@class='hd']) = %locator%]
138 XPATH
139         , 'icon' => <<<XPATH
140 .//*[contains(concat(' ', normalize-space(@class), ' '), ' icon ') and ( contains(normalize-space(@title), %locator%))]
141 XPATH
142         , 'list_item' => <<<XPATH
143 .//li[contains(normalize-space(.), %locator%) and not(.//li[contains(normalize-space(.), %locator%)])]
144 XPATH
145         , 'question' => <<<XPATH
146 .//div[contains(concat(' ', normalize-space(@class), ' '), ' que ')]
147     [contains(div[@class='content']/div[contains(concat(' ', normalize-space(@class), ' '), ' formulation ')], %locator%)]
148 XPATH
149         , 'region' => <<<XPATH
150 .//*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%]
151 XPATH
152         , 'section' => <<<XPATH
153 .//li[contains(concat(' ', normalize-space(@class), ' '), ' section ')][./descendant::*[self::h3]
154     [normalize-space(.) = %locator%][contains(concat(' ', normalize-space(@class), ' '), ' sectionname ') or
155     contains(concat(' ', normalize-space(@class), ' '), ' section-title ')]] |
156 .//div[contains(concat(' ', normalize-space(@class), ' '), ' sitetopic ')]
157     [./descendant::*[self::h2][normalize-space(.) = %locator%] or %locator% = 'frontpage']
158 XPATH
159         , 'table' => <<<XPATH
160 .//table[(./@id = %locator% or contains(.//caption, %locator%) or contains(.//th, %locator%) or contains(concat(' ', normalize-space(@class), ' '), %locator% ))]
161 XPATH
162         , 'table_row' => <<<XPATH
163 .//tr[contains(normalize-space(.), %locator%) and not(.//tr[contains(normalize-space(.), %locator%)])]
164 XPATH
165         , 'text' => <<<XPATH
166 .//*[contains(., %locator%) and not(.//*[contains(., %locator%)])]
167 XPATH
168         , 'form_row' => <<<XPATH
169 .//*[self::label or self::div[contains(concat(' ', @class, ' '), ' fstaticlabel ')]][contains(., %locator%)]/ancestor::*[contains(concat(' ', @class, ' '), ' fitem ')]
170 XPATH
171         , 'message_area_region' => <<<XPATH
172 .//div[@data-region='messaging-area']/descendant::*[@data-region = %locator%]
173 XPATH
174         , 'message_area_region_content' => <<<XPATH
175 .//div[@data-region='messaging-area']/descendant::*[@data-region-content = %locator%]
176 XPATH
177         , 'message_area_action' => <<<XPATH
178 .//div[@data-region='messaging-area']/descendant::*[@data-action = %locator%]
179 XPATH
180     );
182     protected static $customselectors = [
183         'field' => [
184             'upstream' => <<<XPATH
185 .//*
186 [%fieldFilterWithPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithPlaceholder%]
188 .//label[%tagTextMatch%]//.//*[%fieldFilterWithPlaceholder%][%notFieldTypeFilter%]
190 .//*
191 [%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithoutPlaceholder%]
193 .//label[%tagTextMatch%]//.//*[%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%]
194 XPATH
195         ,
196             'filemanager' => <<<XPATH
197 .//*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker']
198     /descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
199 XPATH
200         ,
201              'passwordunmask' => <<<XPATH
202 .//*[@data-passwordunmask='wrapper']
203     /descendant::input[@id = %locator% or @id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
204 XPATH
205         ],
206     ];
208     /**
209      * Mink comes with a number of named replacements.
210      * Sometimes we want to add our own.
211      *
212      * @var array XPaths for moodle elements.
213      */
214     protected static $customreplacements = [
215         '%buttonMatch%' => [
216             'upstream' => '%idOrNameMatch% or %valueMatch% or %titleMatch%',
217             'aria' => '%ariaLabelMatch%',
218         ],
219         '%ariaLabelMatch%' => [
220             'moodle' => 'contains(./@aria-label, %locator%)',
221         ],
222     ];
224     /**
225      * Allowed selectors getter.
226      *
227      * @return array
228      */
229     public static function get_allowed_selectors() {
230         return static::$allowedselectors;
231     }
233     /**
234      * Allowed text selectors getter.
235      *
236      * @return array
237      */
238     public static function get_allowed_text_selectors() {
239         return static::$allowedtextselectors;
240     }