Commit | Line | Data |
---|---|---|
23ebc481 DM |
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 | * Steps definitions related with forms. | |
19 | * | |
20 | * @package core | |
21 | * @category test | |
22 | * @copyright 2012 David Monllaó | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
26 | // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. | |
27 | ||
28 | require_once(__DIR__ . '/../../../lib/behat/behat_base.php'); | |
29 | ||
30 | use Behat\Behat\Context\Step\Given as Given, | |
31 | Behat\Behat\Context\Step\When as When, | |
32 | Behat\Behat\Context\Step\Then as Then, | |
33 | Behat\Gherkin\Node\TableNode as TableNode, | |
34 | Behat\Mink\Element\NodeElement as NodeElement, | |
35 | Behat\Mink\Exception\ExpectationException as ExpectationException, | |
36 | Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException; | |
37 | ||
38 | /** | |
39 | * Forms-related steps definitions. | |
40 | * | |
41 | * @package core | |
42 | * @category test | |
43 | * @copyright 2012 David Monllaó | |
44 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
45 | */ | |
46 | class behat_forms extends behat_base { | |
47 | ||
48 | /** | |
49 | * Presses button with specified id|name|title|alt|value. | |
50 | * | |
51 | * @see Behat\MinkExtension\Context\MinkContext | |
52 | * @When /^I press "(?P<button_string>(?:[^"]|\\")*)"$/ | |
53 | */ | |
54 | public function press_button($button) { | |
55 | $button = $this->fixStepArgument($button); | |
56 | $this->getSession()->getPage()->pressButton($button); | |
57 | } | |
58 | ||
59 | /** | |
60 | * Fills a moodle form with field/value data. | |
61 | * | |
62 | * @throws ElementNotFoundException | |
63 | * @Given /^I fill the moodle form with:$/ | |
64 | * @param TableNode $data | |
65 | */ | |
66 | public function i_fill_the_moodle_form_with(TableNode $data) { | |
67 | ||
68 | $datahash = $data->getRowsHash(); | |
69 | ||
70 | // The action depends on the field type. | |
71 | foreach ($datahash as $locator => $value) { | |
72 | ||
73 | unset($fieldnode); | |
74 | ||
75 | // Removing \\ that escapes " of the steps arguments. | |
76 | $locator = $this->fixStepArgument($locator); | |
77 | ||
78 | // Finds the element in the page waiting until it appears (or timeouts) | |
79 | // otherwise spin() throws exception. | |
80 | $exception = new ElementNotFoundException( | |
81 | $this->getSession(), 'form field', 'id|name|label|value', $locator | |
82 | ); | |
83 | ||
84 | // $context is $this and will be passed to the function by spin(). | |
85 | $args['locator'] = $locator; | |
86 | ||
87 | // Closure to ensure field($locator) exists. | |
88 | $fieldnode = $this->spin( | |
89 | function($context, $args) { | |
90 | return $context->getSession()->getPage()->findField($args['locator']); | |
91 | }, $exception, $args | |
92 | ); | |
93 | ||
94 | // Gets the field type from a parent node. | |
95 | $field = $this->get_field($fieldnode, $locator); | |
96 | ||
97 | // Delegates to the field class. | |
98 | $value = $this->fixStepArgument($value); | |
99 | $field->set_value($value); | |
100 | } | |
101 | } | |
102 | ||
103 | /** | |
104 | * Fills in form field with specified id|name|label|value. | |
105 | * | |
106 | * @see Behat\MinkExtension\Context\MinkContext | |
107 | * @When /^I fill in "(?P<field_string>(?:[^"]|\\")*)" with "(?P<value_string>(?:[^"]|\\")*)"$/ | |
108 | */ | |
109 | public function fill_field($field, $value) { | |
110 | $field = $this->fixStepArgument($field); | |
111 | $value = $this->fixStepArgument($value); | |
112 | $this->getSession()->getPage()->fillField($field, $value); | |
113 | } | |
114 | ||
115 | /** | |
116 | * Selects option in select field with specified id|name|label|value. | |
117 | * | |
118 | * @see Behat\MinkExtension\Context\MinkContext | |
119 | * @throws ElementNotFoundException | |
120 | * @When /^I select "(?P<option_string>(?:[^"]|\\")*)" from "(?P<select_string>(?:[^"]|\\")*)"$/ | |
121 | */ | |
122 | public function select_option($option, $select) { | |
123 | $select = $this->fixStepArgument($select); | |
124 | $option = $this->fixStepArgument($option); | |
125 | ||
126 | // We add the click event to deal with autosubmit drop down menus. | |
127 | $selectnode = $this->getSession()->getPage()->findField($select); | |
128 | if ($selectnode == null) { | |
129 | throw new ElementNotFoundException( | |
130 | $this->getSession(), 'form field', 'id|name|label|value', $select | |
131 | ); | |
132 | } | |
133 | $selectnode->selectOption($option); | |
134 | $selectnode->click(); | |
135 | } | |
136 | ||
137 | /** | |
138 | * Checks checkbox with specified id|name|label|value. | |
139 | * | |
140 | * @see Behat\MinkExtension\Context\MinkContext | |
141 | * @When /^I check "(?P<option_string>(?:[^"]|\\")*)"$/ | |
142 | */ | |
143 | public function check_option($option) { | |
144 | $option = $this->fixStepArgument($option); | |
145 | $this->getSession()->getPage()->checkField($option); | |
146 | } | |
147 | ||
148 | /** | |
149 | * Unchecks checkbox with specified id|name|label|value. | |
150 | * | |
151 | * @see Behat\MinkExtension\Context\MinkContext | |
152 | * @When /^I uncheck "(?P<option_string>(?:[^"]|\\")*)"$/ | |
153 | */ | |
154 | public function uncheck_option($option) { | |
155 | $option = $this->fixStepArgument($option); | |
156 | $this->getSession()->getPage()->uncheckField($option); | |
157 | } | |
158 | ||
159 | /** | |
160 | * Checks that the form element field have the specified value. | |
161 | * | |
162 | * @throws ElementNotFoundException | |
163 | * @throws ExpectationException | |
164 | * @Then /^the "(?P<field_string>(?:[^"]|\\")*)" field should match "(?P<value_string>(?:[^"]|\\")*)" value$/ | |
165 | * @param mixed $locator | |
166 | * @param mixed $value | |
167 | */ | |
168 | public function the_field_should_match_value($locator, $value) { | |
169 | ||
170 | $locator = $this->fixStepArgument($locator); | |
171 | $value = $this->fixStepArgument($value); | |
172 | ||
173 | $fieldnode = $this->getSession()->getPage()->findField($locator); | |
174 | if (null === $fieldnode) { | |
175 | throw new ElementNotFoundException( | |
176 | $this->getSession(), 'form field', 'id|name|label|value', $locator | |
177 | ); | |
178 | } | |
179 | ||
180 | // Gets the field instance. | |
181 | $field = $this->get_field($fieldnode, $locator); | |
182 | ||
183 | // Checks if the provided value matches the current field value. | |
184 | if ($value != $field->get_value()) { | |
185 | throw new ExpectationException( | |
186 | 'The \'' . $locator . '\' value is \'' . $field->get_value() . '\'' , | |
187 | $this->getSession() | |
188 | ); | |
189 | } | |
190 | } | |
191 | ||
192 | /** | |
193 | * Checks, that checkbox with specified in|name|label|value is checked. | |
194 | * | |
195 | * @see Behat\MinkExtension\Context\MinkContext | |
196 | * @Then /^the "(?P<checkbox_string>(?:[^"]|\\")*)" checkbox should be checked$/ | |
197 | */ | |
198 | public function assert_checkbox_checked($checkbox) { | |
199 | $checkbox = $this->fixStepArgument($checkbox); | |
200 | $this->assertSession()->checkboxChecked($checkbox); | |
201 | } | |
202 | ||
203 | /** | |
204 | * Checks, that checkbox with specified in|name|label|value is unchecked. | |
205 | * | |
206 | * @see Behat\MinkExtension\Context\MinkContext | |
207 | * @Then /^the "(?P<checkbox_string>(?:[^"]|\\")*)" checkbox should not be checked$/ | |
208 | */ | |
209 | public function assert_checkbox_not_checked($checkbox) { | |
210 | $checkbox = $this->fixStepArgument($checkbox); | |
211 | $this->assertSession()->checkboxNotChecked($checkbox); | |
212 | } | |
213 | ||
214 | /** | |
215 | * Checks, that given select box contains the specified option. | |
216 | * | |
217 | * @throws ExpectationException | |
218 | * @throws ElementNotFoundException | |
219 | * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should contain "(?P<option_string>(?:[^"]|\\")*)"$/ | |
220 | * @param string $select The select element name | |
221 | * @param string $option The option text/value | |
222 | */ | |
223 | public function the_select_box_should_contain($select, $option) { | |
224 | ||
225 | $select = $this->fixStepArgument($select); | |
226 | $option = $this->fixStepArgument($option); | |
227 | ||
228 | $selectnode = $this->getSession()->getPage()->findField($select); | |
229 | if ($selectnode == null) { | |
230 | throw new ElementNotFoundException( | |
231 | $this->getSession(), 'form field', 'id|name|label|value', $select | |
232 | ); | |
233 | } | |
234 | ||
235 | $regex = '/' . preg_quote($option, '/') . '/ui'; | |
236 | if (!preg_match($regex, $selectnode->getText())) { | |
237 | throw new ExpectationException( | |
238 | 'The select box "' . $select . '" does not contains the option "' . $option . '"', | |
239 | $this->getSession() | |
240 | ); | |
241 | } | |
242 | ||
243 | } | |
244 | ||
245 | /** | |
246 | * Checks, that given select box does not contain the specified option. | |
247 | * | |
248 | * @throws ExpectationException | |
249 | * @throws ElementNotFoundException | |
250 | * @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should not contain "(?P<option_string>(?:[^"]|\\")*)"$/ | |
251 | * @param string $select The select element name | |
252 | * @param string $option The option text/value | |
253 | */ | |
254 | public function the_select_box_should_not_contain($select, $option) { | |
255 | ||
256 | $select = $this->fixStepArgument($select); | |
257 | $option = $this->fixStepArgument($option); | |
258 | ||
259 | $selectnode = $this->getSession()->getPage()->findField($select); | |
260 | if ($selectnode == null) { | |
261 | throw new ElementNotFoundException( | |
262 | $this->getSession(), 'form field', 'id|name|label|value', $select | |
263 | ); | |
264 | } | |
265 | ||
266 | $regex = '/' . preg_quote($option, '/') . '/ui'; | |
267 | if (preg_match($regex, $selectnode->getText())) { | |
268 | throw new ExpectationException( | |
269 | 'The select box "' . $select . '" contains the option "' . $option . '"', | |
270 | $this->getSession() | |
271 | ); | |
272 | } | |
273 | } | |
274 | ||
275 | /** | |
276 | * Gets an instance of the form element field. | |
277 | * | |
278 | * @param NodeElement $fieldnode The current node | |
279 | * @param string $locator Just to send an exception that makes sense for the user | |
280 | * @return behat_form_field | |
281 | */ | |
282 | protected function get_field(NodeElement $fieldnode, $locator) { | |
283 | global $CFG; | |
284 | ||
285 | $locator = $this->fixStepArgument($locator); | |
286 | ||
287 | // Get the field type. | |
288 | $type = $this->get_node_type($fieldnode, $locator); | |
289 | $classname = 'behat_form_' . $type; | |
290 | ||
291 | // Fallsback on the default form field if nothing specific exists. | |
292 | $classpath = $CFG->libdir . '/behat/form_field/' . $classname . '.php'; | |
293 | if (!file_exists($classpath)) { | |
294 | $classname = 'behat_form_field'; | |
295 | $classpath = $CFG->libdir . '/behat/form_field/' . $classname . '.php'; | |
296 | } | |
297 | ||
298 | // Returns the instance. | |
299 | require_once($classpath); | |
300 | return new $classname($this->getSession(), $fieldnode); | |
301 | } | |
302 | ||
303 | /** | |
304 | * Recursive method to find the field type. | |
305 | * | |
306 | * Depending on the field the felement class node is a level or in another. We | |
307 | * look recursively for a parent node with a 'felement' class to find the field type. | |
308 | * | |
309 | * @throws ExpectationException | |
310 | * @param NodeElement $fieldnode The current node | |
311 | * @param string $locator Just to send an exception that makes sense for the user | |
312 | * @return mixed String or NodeElement depending if we have reached the felement node | |
313 | */ | |
314 | protected function get_node_type(NodeElement $fieldnode, $locator) { | |
315 | ||
316 | $locator = $this->fixStepArgument($locator); | |
317 | ||
318 | // We look for a parent node with 'felement' class. | |
319 | if ($class = $fieldnode->getParent()->getAttribute('class')) { | |
320 | ||
321 | if (strstr($class, 'felement') != false) { | |
322 | // Remove 'felement f' from class value. | |
323 | return substr($class, 10); | |
324 | } | |
325 | ||
326 | // Stop propagation through the DOM, something went wrong!. | |
327 | if (strstr($class, 'fcontainer') != false) { | |
328 | throw new ExpectationException('No field type for ' . $locator . ' found, ensure the field exists', $this->getSession()); | |
329 | } | |
330 | } | |
331 | ||
332 | return $this->get_node_type($fieldnode->getParent(), $locator); | |
333 | } | |
334 | ||
335 | } |