Commit | Line | Data |
---|---|---|
786ea937 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 | * General use steps definitions. | |
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__ . '/../../behat/behat_base.php'); | |
29 | ||
ca4f33a7 DM |
30 | use Behat\Mink\Exception\ExpectationException as ExpectationException, |
31 | Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException; | |
786ea937 DM |
32 | |
33 | /** | |
34 | * Cross component steps definitions. | |
35 | * | |
36 | * Basic web application definitions from MinkExtension and | |
37 | * BehatchExtension. Definitions modified according to our needs | |
38 | * when necessary and including only the ones we need to avoid | |
39 | * overlapping and confusion. | |
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_general extends behat_base { | |
47 | ||
48 | /** | |
49 | * Opens Moodle homepage. | |
50 | * | |
786ea937 DM |
51 | * @Given /^I am on homepage$/ |
52 | */ | |
53 | public function i_am_on_homepage() { | |
40923977 | 54 | $this->getSession()->visit($this->locate_path('/')); |
786ea937 DM |
55 | } |
56 | ||
18c84063 DM |
57 | /** |
58 | * Reloads the current page. | |
59 | * | |
60 | * @Given /^I reload the page$/ | |
61 | */ | |
62 | public function reload() { | |
63 | $this->getSession()->reload(); | |
64 | } | |
65 | ||
1303eb29 DM |
66 | /** |
67 | * Switches to the specified window. Useful when interacting with popup windows. | |
68 | * | |
69 | * @Given /^I switch to "(?P<window_name_string>(?:[^"]|\\")*)" window$/ | |
70 | * @param string $windowname | |
71 | */ | |
72 | public function switch_to_window($windowname) { | |
73 | $this->getSession()->switchToWindow($windowname); | |
74 | } | |
75 | ||
76 | /** | |
77 | * Switches to the main Moodle window. Useful when you finish interacting with popup windows. | |
78 | * | |
79 | * @Given /^I switch to the main window$/ | |
80 | */ | |
81 | public function switch_to_the_main_window() { | |
82 | $this->getSession()->switchToWindow(); | |
83 | } | |
84 | ||
563514b1 | 85 | /** |
7daab401 | 86 | * Accepts the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental. |
563514b1 DM |
87 | * @Given /^I accept the currently displayed dialog$/ |
88 | */ | |
89 | public function accept_currently_displayed_alert_dialog() { | |
90 | $this->getSession()->getDriver()->getWebDriverSession()->accept_alert(); | |
91 | } | |
92 | ||
786ea937 DM |
93 | /** |
94 | * Clicks link with specified id|title|alt|text. | |
95 | * | |
786ea937 | 96 | * @When /^I follow "(?P<link_string>(?:[^"]|\\")*)"$/ |
1f9ffbdb | 97 | * @throws ElementNotFoundException Thrown by behat_base::find |
40923977 | 98 | * @param string $link |
786ea937 DM |
99 | */ |
100 | public function click_link($link) { | |
1f9ffbdb DM |
101 | |
102 | $linknode = $this->find_link($link); | |
103 | $linknode->click(); | |
786ea937 DM |
104 | } |
105 | ||
106 | /** | |
107 | * Waits X seconds. Required after an action that requires data from an AJAX request. | |
108 | * | |
109 | * @Then /^I wait "(?P<seconds_number>\d+)" seconds$/ | |
110 | * @param int $seconds | |
111 | */ | |
112 | public function i_wait_seconds($seconds) { | |
113 | $this->getSession()->wait($seconds * 1000, false); | |
114 | } | |
115 | ||
116 | /** | |
117 | * Waits until the page is completely loaded. This step is auto-executed after every step. | |
118 | * | |
119 | * @Given /^I wait until the page is ready$/ | |
120 | */ | |
121 | public function wait_until_the_page_is_ready() { | |
122 | $this->getSession()->wait(self::TIMEOUT, '(document.readyState === "complete")'); | |
123 | } | |
124 | ||
125 | /** | |
40923977 | 126 | * Generic mouse over action. Mouse over a element of the specified type. |
786ea937 | 127 | * |
40923977 DM |
128 | * @When /^I hover "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/ |
129 | * @param string $element Element we look for | |
130 | * @param string $selectortype The type of what we look for | |
786ea937 | 131 | */ |
40923977 | 132 | public function i_hover($element, $selectortype) { |
1f9ffbdb | 133 | |
40923977 DM |
134 | // Gets the node based on the requested selector type and locator. |
135 | $node = $this->get_selected_node($selectortype, $element); | |
786ea937 DM |
136 | $node->mouseOver(); |
137 | } | |
138 | ||
40923977 DM |
139 | /** |
140 | * Generic click action. Click on the element of the specified type. | |
141 | * | |
142 | * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/ | |
143 | * @param string $element Element we look for | |
144 | * @param string $selectortype The type of what we look for | |
145 | */ | |
146 | public function i_click_on($element, $selectortype) { | |
147 | ||
148 | // Gets the node based on the requested selector type and locator. | |
149 | $node = $this->get_selected_node($selectortype, $element); | |
150 | $node->click(); | |
151 | } | |
152 | ||
072f67fc DM |
153 | /** |
154 | * Click on the element of the specified type which is located inside the second element. | |
155 | * | |
156 | * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/ | |
157 | * @param string $element Element we look for | |
158 | * @param string $selectortype The type of what we look for | |
159 | * @param string $nodeelement Element we look in | |
160 | * @param string $nodeselectortype The type of selector where we look in | |
161 | */ | |
162 | public function i_click_on_in_the($element, $selectortype, $nodeelement, $nodeselectortype) { | |
163 | ||
164 | $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement); | |
165 | $node->click(); | |
166 | } | |
167 | ||
f9d3667e DM |
168 | /** |
169 | * Click on the specified element inside a table row containing the specified text. | |
170 | * | |
171 | * @Given /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" in the "(?P<row_text_string>(?:[^"]|\\")*)" table row$/ | |
172 | * @throws ElementNotFoundException | |
173 | * @param string $element Element we look for | |
174 | * @param string $selectortype The type of what we look for | |
175 | * @param string $tablerowtext The table row text | |
176 | */ | |
177 | public function i_click_on_in_the_table_row($element, $selectortype, $tablerowtext) { | |
178 | ||
179 | // The table row container. | |
180 | $nocontainerexception = new ElementNotFoundException($this->getSession(), '"' . $tablerowtext . '" row text '); | |
181 | $tablerowtext = str_replace("'", "\'", $tablerowtext); | |
182 | $rownode = $this->find('xpath', "//tr[contains(., '" . $tablerowtext . "')]", $nocontainerexception); | |
183 | ||
184 | // Looking for the element DOM node inside the specified row. | |
185 | list($selector, $locator) = $this->transform_selector($selectortype, $element); | |
186 | $elementnode = $this->find($selector, $locator, false, $rownode); | |
187 | $elementnode->click(); | |
188 | } | |
189 | ||
563514b1 | 190 | /** |
7daab401 | 191 | * Drags and drops the specified element to the specified container. This step does not work in all the browsers, consider it experimental. |
563514b1 DM |
192 | * |
193 | * The steps definitions calling this step as part of them should | |
194 | * manage the wait times by themselves as the times and when the | |
195 | * waits should be done depends on what is being dragged & dropper. | |
196 | * | |
197 | * @Given /^I drag "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" and I drop it in "(?P<container_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/ | |
198 | * @param string $element | |
199 | * @param string $selectortype | |
200 | * @param string $containerelement | |
201 | * @param string $containerselectortype | |
202 | */ | |
203 | public function i_drag_and_i_drop_it_in($element, $selectortype, $containerelement, $containerselectortype) { | |
204 | ||
205 | list($sourceselector, $sourcelocator) = $this->transform_selector($selectortype, $element); | |
206 | $sourcexpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($sourceselector, $sourcelocator); | |
207 | ||
208 | list($containerselector, $containerlocator) = $this->transform_selector($containerselectortype, $containerelement); | |
209 | $destinationxpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($containerselector, $containerlocator); | |
210 | ||
211 | $this->getSession()->getDriver()->dragTo($sourcexpath, $destinationxpath); | |
212 | } | |
213 | ||
786ea937 DM |
214 | /** |
215 | * Checks, that page contains specified text. | |
216 | * | |
786ea937 | 217 | * @Then /^I should see "(?P<text_string>(?:[^"]|\\")*)"$/ |
9a1f4922 | 218 | * @throws ExpectationException |
40923977 | 219 | * @param string $text |
786ea937 DM |
220 | */ |
221 | public function assert_page_contains_text($text) { | |
9a1f4922 DM |
222 | |
223 | $xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text); | |
224 | $xpath = "/descendant::*[contains(., " . $xpathliteral. ")]"; | |
225 | ||
226 | // Wait until it finds the text, otherwise custom exception. | |
227 | try { | |
228 | $this->find('xpath', $xpath); | |
229 | } catch (ElementNotFoundException $e) { | |
230 | throw new ExpectationException('"' . $text . '" text was not found in the page', $this->getSession()); | |
231 | } | |
786ea937 DM |
232 | } |
233 | ||
234 | /** | |
235 | * Checks, that page doesn't contain specified text. | |
236 | * | |
786ea937 | 237 | * @Then /^I should not see "(?P<text_string>(?:[^"]|\\")*)"$/ |
9a1f4922 | 238 | * @throws ExpectationException |
40923977 | 239 | * @param string $text |
786ea937 DM |
240 | */ |
241 | public function assert_page_not_contains_text($text) { | |
9a1f4922 DM |
242 | |
243 | $xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text); | |
244 | $xpath = "/descendant::*[not(contains(., " . $xpathliteral. "))]"; | |
245 | ||
246 | // Wait until it finds the text, otherwise custom exception. | |
247 | try { | |
248 | $this->find('xpath', $xpath); | |
249 | } catch (ElementNotFoundException $e) { | |
250 | throw new ExpectationException('"' . $text . '" text was found in the page', $this->getSession()); | |
251 | } | |
786ea937 DM |
252 | } |
253 | ||
254 | /** | |
40923977 | 255 | * Checks, that element with specified CSS selector or XPath contains specified text. |
786ea937 | 256 | * |
40923977 DM |
257 | * @Then /^I should see "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/ |
258 | * @param string $text | |
259 | * @param string $element Element we look in. | |
260 | * @param string $selectortype The type of element where we are looking in. | |
786ea937 | 261 | */ |
40923977 DM |
262 | public function assert_element_contains_text($text, $element, $selectortype) { |
263 | ||
264 | // Transforming from steps definitions selector/locator format to Mink format. | |
072f67fc | 265 | list($selector, $locator) = $this->transform_text_selector($selectortype, $element); |
40923977 | 266 | $this->assertSession()->elementTextContains($selector, $locator, $text); |
786ea937 DM |
267 | } |
268 | ||
269 | /** | |
40923977 | 270 | * Checks, that element with specified CSS selector or XPath doesn't contain specified text. |
786ea937 | 271 | * |
40923977 DM |
272 | * @Then /^I should not see "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/ |
273 | * @param string $text | |
274 | * @param string $element Element we look in. | |
275 | * @param string $selectortype The type of element where we are looking in. | |
786ea937 | 276 | */ |
40923977 DM |
277 | public function assert_element_not_contains_text($text, $element, $selectortype) { |
278 | ||
279 | // Transforming from steps definitions selector/locator format to mink format. | |
072f67fc | 280 | list($selector, $locator) = $this->transform_text_selector($selectortype, $element); |
40923977 | 281 | $this->assertSession()->elementTextNotContains($selector, $locator, $text); |
786ea937 DM |
282 | } |
283 | ||
60054942 DM |
284 | /** |
285 | * Checks, that the first specified element appears before the second one. | |
286 | * | |
287 | * @Given /^"(?P<preceding_element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" should appear before "(?P<following_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/ | |
288 | * @throws ExpectationException | |
289 | * @param string $preelement The locator of the preceding element | |
290 | * @param string $preselectortype The locator of the preceding element | |
291 | * @param string $postelement The locator of the latest element | |
292 | * @param string $postselectortype The selector type of the latest element | |
293 | */ | |
294 | public function should_appear_before($preelement, $preselectortype, $postelement, $postselectortype) { | |
295 | ||
296 | // We allow postselectortype as a non-text based selector. | |
297 | list($preselector, $prelocator) = $this->transform_selector($preselectortype, $preelement); | |
298 | list($postselector, $postlocator) = $this->transform_selector($postselectortype, $postelement); | |
299 | ||
300 | $prexpath = $this->find($preselector, $prelocator)->getXpath(); | |
301 | $postxpath = $this->find($postselector, $postlocator)->getXpath(); | |
302 | ||
303 | // Using following xpath axe to find it. | |
304 | $msg = '"'.$preelement.'" "'.$preselectortype.'" does not appear before "'.$postelement.'" "'.$postselectortype.'"'; | |
305 | $xpath = $prexpath.'/following::*[contains(., '.$postxpath.')]'; | |
306 | if (!$this->getSession()->getDriver()->find($xpath)) { | |
307 | throw new ExpectationException($msg, $this->getSession()); | |
308 | } | |
309 | } | |
310 | ||
311 | /** | |
312 | * Checks, that the first specified element appears after the second one. | |
313 | * | |
314 | * @Given /^"(?P<following_element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" should appear after "(?P<preceding_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/ | |
315 | * @throws ExpectationException | |
316 | * @param string $postelement The locator of the latest element | |
317 | * @param string $postselectortype The selector type of the latest element | |
318 | * @param string $preelement The locator of the preceding element | |
319 | * @param string $preselectortype The locator of the preceding element | |
320 | */ | |
321 | public function should_appear_after($postelement, $postselectortype, $preelement, $preselectortype) { | |
322 | ||
323 | // We allow postselectortype as a non-text based selector. | |
324 | list($postselector, $postlocator) = $this->transform_selector($postselectortype, $postelement); | |
325 | list($preselector, $prelocator) = $this->transform_selector($preselectortype, $preelement); | |
326 | ||
327 | $postxpath = $this->find($postselector, $postlocator)->getXpath(); | |
328 | $prexpath = $this->find($preselector, $prelocator)->getXpath(); | |
329 | ||
330 | // Using preceding xpath axe to find it. | |
331 | $msg = '"'.$postelement.'" "'.$postselectortype.'" does not appear after "'.$preelement.'" "'.$preselectortype.'"'; | |
332 | $xpath = $postxpath.'/preceding::*[contains(., '.$prexpath.')]'; | |
333 | if (!$this->getSession()->getDriver()->find($xpath)) { | |
334 | throw new ExpectationException($msg, $this->getSession()); | |
335 | } | |
336 | } | |
337 | ||
786ea937 | 338 | /** |
40923977 | 339 | * Checks, that element of specified type is disabled. |
786ea937 | 340 | * |
40923977 | 341 | * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be disabled$/ |
1f9ffbdb | 342 | * @throws ExpectationException Thrown by behat_base::find |
40923977 DM |
343 | * @param string $element Element we look in |
344 | * @param string $selectortype The type of element where we are looking in. | |
786ea937 | 345 | */ |
40923977 | 346 | public function the_element_should_be_disabled($element, $selectortype) { |
786ea937 | 347 | |
40923977 DM |
348 | // Transforming from steps definitions selector/locator format to Mink format and getting the NodeElement. |
349 | $node = $this->get_selected_node($selectortype, $element); | |
786ea937 DM |
350 | |
351 | if (!$node->hasAttribute('disabled')) { | |
352 | throw new ExpectationException('The element "' . $element . '" is not disabled', $this->getSession()); | |
353 | } | |
354 | } | |
355 | ||
356 | /** | |
40923977 | 357 | * Checks, that element of specified type is enabled. |
786ea937 | 358 | * |
40923977 | 359 | * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be enabled$/ |
1f9ffbdb | 360 | * @throws ExpectationException Thrown by behat_base::find |
40923977 DM |
361 | * @param string $element Element we look on |
362 | * @param string $selectortype The type of where we look | |
786ea937 | 363 | */ |
40923977 | 364 | public function the_element_should_be_enabled($element, $selectortype) { |
1f9ffbdb | 365 | |
40923977 DM |
366 | // Transforming from steps definitions selector/locator format to mink format and getting the NodeElement. |
367 | $node = $this->get_selected_node($selectortype, $element); | |
786ea937 DM |
368 | |
369 | if ($node->hasAttribute('disabled')) { | |
370 | throw new ExpectationException('The element "' . $element . '" is not enabled', $this->getSession()); | |
371 | } | |
372 | } | |
373 | ||
ca4f33a7 | 374 | /** |
62eb5c46 EL |
375 | * Checks the provided element and selector type exists in the current page. |
376 | * | |
377 | * This step is for advanced users, use it if you don't find anything else suitable for what you need. | |
ca4f33a7 DM |
378 | * |
379 | * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should exists$/ | |
380 | * @throws ElementNotFoundException Thrown by behat_base::find | |
381 | * @param string $element The locator of the specified selector | |
382 | * @param string $selectortype The selector type | |
383 | */ | |
384 | public function should_exists($element, $selectortype) { | |
385 | ||
386 | // Getting Mink selector and locator. | |
387 | list($selector, $locator) = $this->transform_selector($selectortype, $element); | |
388 | ||
389 | // Will throw an ElementNotFoundException if it does not exist. | |
390 | $this->find($selector, $locator); | |
391 | } | |
392 | ||
393 | /** | |
62eb5c46 EL |
394 | * Checks that the provided element and selector type not exists in the current page. |
395 | * | |
396 | * This step is for advanced users, use it if you don't find anything else suitable for what you need. | |
ca4f33a7 DM |
397 | * |
398 | * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not exists$/ | |
399 | * @throws ExpectationException | |
400 | * @param string $element The locator of the specified selector | |
401 | * @param string $selectortype The selector type | |
402 | */ | |
403 | public function should_not_exists($element, $selectortype) { | |
404 | ||
405 | try { | |
406 | $this->should_exists($element, $selectortype); | |
407 | throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the current page', $this->getSession()); | |
62eb5c46 | 408 | } catch (ElementNotFoundException $e) { |
ca4f33a7 DM |
409 | // It passes. |
410 | return; | |
411 | } | |
412 | } | |
413 | ||
786ea937 | 414 | } |