MDL-37750 behat: Waiting for DOM ready
[moodle.git] / lib / tests / behat / behat_forms.php
CommitLineData
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
28require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
29
30use 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 */
46class 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}