mirrored from git://git.moodle.org/moodle.git
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
/
behat_forms.php
390 lines (325 loc) · 13.8 KB
/
behat_forms.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Steps definitions related with forms.
*
* @package core
* @category test
* @copyright 2012 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
use Behat\Behat\Context\Step\Given as Given,
Behat\Behat\Context\Step\When as When,
Behat\Behat\Context\Step\Then as Then,
Behat\Gherkin\Node\TableNode as TableNode,
Behat\Mink\Element\NodeElement as NodeElement,
Behat\Mink\Exception\ExpectationException as ExpectationException,
Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
/**
* Forms-related steps definitions.
*
* @package core
* @category test
* @copyright 2012 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_forms extends behat_base {
/**
* Presses button with specified id|name|title|alt|value.
*
* @When /^I press "(?P<button_string>(?:[^"]|\\")*)"$/
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $button
*/
public function press_button($button) {
// Ensures the button is present.
$buttonnode = $this->find_button($button);
$buttonnode->press();
}
/**
* Fills a moodle form with field/value data.
*
* @Given /^I fill the moodle form with:$/
* @throws ElementNotFoundException Thrown by behat_base::find
* @param TableNode $data
*/
public function i_fill_the_moodle_form_with(TableNode $data) {
// Expand all fields in case we have.
$this->expand_all_fields();
$datahash = $data->getRowsHash();
// The action depends on the field type.
foreach ($datahash as $locator => $value) {
unset($fieldnode);
// Getting the NodeElement.
$fieldnode = $this->find_field($locator);
// Gets the field type from a parent node.
$field = $this->get_field($fieldnode, $locator);
// Delegates to the field class.
$field->set_value($value);
}
}
/**
* Expands all moodleform's fields, including collapsed fieldsets and advanced fields if they are present.
* @Given /^I expand all fieldsets$/
*/
public function i_expand_all_fieldsets() {
$this->expand_all_fields();
}
/**
* Expands all moodle form fieldsets if they exists.
*
* Externalized from i_expand_all_fields to call it from
* other form-related steps without having to use steps-group calls.
*
* @throws ElementNotFoundException Thrown by behat_base::find_all
* @return void
*/
protected function expand_all_fields() {
// behat_base::find() throws an exception if there are no elements, we should not fail a test because of this.
try {
// Expand fieldsets.
$fieldsets = $this->find_all('css', 'fieldset.collapsed a.fheader');
// We are supposed to have fieldsets here, otherwise exception.
// Funny thing about this, with find_all() we specify a pattern and each element matching the pattern is added to the array
// with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath
// anymore (is not collapsed) so [1] becomes [0], that's why we always click on the first XPath match, will be always the next one.
$iterations = count($fieldsets);
for ($i = 0; $i < $iterations; $i++) {
$fieldsets[0]->click();
}
} catch (ElementNotFoundException $e) {
// We continue if there are not expanded fields.
}
// Different try & catch as we can have expanded fieldsets with advanced fields on them.
try {
// Show all fields.
$showmorestr = get_string('showmore', 'form');
$showmores = $this->find_all('xpath', "//a[contains(concat(' ', normalize-space(.), ' '), '" . $showmorestr . "')][contains(concat(' ', normalize-space(@class), ' '), ' morelesstoggler')]");
// We are supposed to have 'show more's here, otherwise exception.
// Same funny case, after clicking on the element the [1] showmore link becomes the [0].
$iterations = count($showmores);
for ($i = 0; $i < $iterations; $i++) {
$showmores[0]->click();
}
} catch (ElementNotFoundException $e) {
// We continue with the test.
}
}
/**
* Fills in form field with specified id|name|label|value.
*
* @When /^I fill in "(?P<field_string>(?:[^"]|\\")*)" with "(?P<value_string>(?:[^"]|\\")*)"$/
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $field
* @param string $value
*/
public function fill_field($field, $value) {
$fieldnode = $this->find_field($field);
$fieldnode->setValue($value);
}
/**
* Selects option in select field with specified id|name|label|value.
*
* @When /^I select "(?P<option_string>(?:[^"]|\\")*)" from "(?P<select_string>(?:[^"]|\\")*)"$/
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $option
* @param string $select
*/
public function select_option($option, $select) {
$selectnode = $this->find_field($select);
$selectnode->selectOption($option);
// Adding a click as Selenium requires it to fire some JS events.
$selectnode->click();
}
/**
* Checks checkbox with specified id|name|label|value.
*
* @When /^I check "(?P<option_string>(?:[^"]|\\")*)"$/
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $option
*/
public function check_option($option) {
$checkboxnode = $this->find_field($option);
$checkboxnode->check();
}
/**
* Unchecks checkbox with specified id|name|label|value.
*
* @When /^I uncheck "(?P<option_string>(?:[^"]|\\")*)"$/
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $option
*/
public function uncheck_option($option) {
$checkboxnode = $this->find_field($option);
$checkboxnode->uncheck();
}
/**
* Checks that the form element field have the specified value.
*
* @Then /^the "(?P<field_string>(?:[^"]|\\")*)" field should match "(?P<value_string>(?:[^"]|\\")*)" value$/
* @throws ExpectationException
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $locator
* @param string $value
*/
public function the_field_should_match_value($locator, $value) {
$fieldnode = $this->find_field($locator);
// Get the field.
$field = $this->get_field($fieldnode, $locator);
$fieldvalue = $field->get_value();
// Checks if the provided value matches the current field value.
if (trim($value) != trim($fieldvalue)) {
throw new ExpectationException(
'The \'' . $locator . '\' value is \'' . $fieldvalue . '\', \'' . $value . '\' expected' ,
$this->getSession()
);
}
}
/**
* Checks, that checkbox with specified in|name|label|value is checked.
*
* @Then /^the "(?P<checkbox_string>(?:[^"]|\\")*)" checkbox should be checked$/
* @see Behat\MinkExtension\Context\MinkContext
* @param string $checkbox
*/
public function assert_checkbox_checked($checkbox) {
$this->assertSession()->checkboxChecked($checkbox);
}
/**
* Checks, that checkbox with specified in|name|label|value is unchecked.
*
* @Then /^the "(?P<checkbox_string>(?:[^"]|\\")*)" checkbox should not be checked$/
* @see Behat\MinkExtension\Context\MinkContext
* @param string $checkbox
*/
public function assert_checkbox_not_checked($checkbox) {
$this->assertSession()->checkboxNotChecked($checkbox);
}
/**
* Checks, that given select box contains the specified option.
*
* @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should contain "(?P<option_string>(?:[^"]|\\")*)"$/
* @throws ExpectationException
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $select The select element name
* @param string $option The option text/value
*/
public function the_select_box_should_contain($select, $option) {
$selectnode = $this->find_field($select);
$regex = '/' . preg_quote($option, '/') . '/ui';
if (!preg_match($regex, $selectnode->getText())) {
throw new ExpectationException(
'The select box "' . $select . '" does not contains the option "' . $option . '"',
$this->getSession()
);
}
}
/**
* Checks, that given select box does not contain the specified option.
*
* @Then /^the "(?P<select_string>(?:[^"]|\\")*)" select box should not contain "(?P<option_string>(?:[^"]|\\")*)"$/
* @throws ExpectationException
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $select The select element name
* @param string $option The option text/value
*/
public function the_select_box_should_not_contain($select, $option) {
$selectnode = $this->find_field($select);
$regex = '/' . preg_quote($option, '/') . '/ui';
if (preg_match($regex, $selectnode->getText())) {
throw new ExpectationException(
'The select box "' . $select . '" contains the option "' . $option . '"',
$this->getSession()
);
}
}
/**
* Gets an instance of the form field.
*
* Not all the fields are part of a moodle form, in this
* cases it fallsback to the generic form field. Also note
* that this generic field type is using a generic setValue()
* method from the Behat API, which is not always good to set
* the value of form elements.
*
* @param NodeElement $fieldnode The current node
* @param string $locator Just to send an exception that makes sense for the user
* @return behat_form_field
*/
protected function get_field(NodeElement $fieldnode, $locator) {
global $CFG;
// Get the field type if is part of a moodleform.
if ($this->is_moodleform_field($fieldnode)) {
$type = $this->get_node_type($fieldnode, $locator);
}
// If is not a moodleforms field use the base field type.
if (empty($type)) {
$type = 'field';
}
$classname = 'behat_form_' . $type;
// Fallsback on the default form field if nothing specific exists.
$classpath = $CFG->libdir . '/behat/form_field/' . $classname . '.php';
if (!file_exists($classpath)) {
$classname = 'behat_form_field';
$classpath = $CFG->libdir . '/behat/form_field/' . $classname . '.php';
}
// Returns the instance.
require_once($classpath);
return new $classname($this->getSession(), $fieldnode);
}
/**
* Detects when the field is a moodleform field type.
*
* Note that there are fields inside moodleforms that are not
* moodleform element; this method can not detect this, this will
* be managed by get_node_type, after failing to find the form
* element element type.
*
* @param NodeElement $fieldnode
* @return bool
*/
protected function is_moodleform_field(NodeElement $fieldnode) {
// We already waited when getting the NodeElement and we don't want an exception if it's not part of a moodleform.
$parentformfound = $fieldnode->find('xpath', "/ancestor::form[contains(concat(' ', normalize-space(@class), ' '), ' mform ')]/fieldset");
return ($parentformfound != false);
}
/**
* Recursive method to find the field type.
*
* Depending on the field the felement class node is a level or in another. We
* look recursively for a parent node with a 'felement' class to find the field type.
*
* @param NodeElement $fieldnode The current node.
* @param string $locator Just to send an exception that makes sense for the user.
* @return mixed A NodeElement if we continue looking for the element type and String or false when we are done.
*/
protected function get_node_type(NodeElement $fieldnode, $locator) {
// We look for a parent node with 'felement' class.
if ($class = $fieldnode->getParent()->getAttribute('class')) {
if (strstr($class, 'felement') != false) {
// Remove 'felement f' from class value.
return substr($class, 10);
}
// Stop propagation through the DOM, if it does not have a felement is not part of a moodle form.
if (strstr($class, 'fcontainer') != false) {
return false;
}
}
return $this->get_node_type($fieldnode->getParent(), $locator);
}
}