[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
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 30 use Behat\Mink\Exception\ExpectationException as ExpectationException, 31 Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException, 32 Behat\Mink\Exception\DriverException as DriverException, 33 WebDriver\Exception\NoSuchElement as NoSuchElement, 34 WebDriver\Exception\StaleElementReference as StaleElementReference, 35 Behat\Gherkin\Node\TableNode as TableNode; 36 37 /** 38 * Cross component steps definitions. 39 * 40 * Basic web application definitions from MinkExtension and 41 * BehatchExtension. Definitions modified according to our needs 42 * when necessary and including only the ones we need to avoid 43 * overlapping and confusion. 44 * 45 * @package core 46 * @category test 47 * @copyright 2012 David Monllaó 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 */ 50 class behat_general extends behat_base { 51 52 /** 53 * @var string used by {@link switch_to_window()} and 54 * {@link switch_to_the_main_window()} to work-around a Chrome browser issue. 55 */ 56 const MAIN_WINDOW_NAME = '__moodle_behat_main_window_name'; 57 58 /** 59 * Opens Moodle homepage. 60 * 61 * @Given /^I am on homepage$/ 62 */ 63 public function i_am_on_homepage() { 64 $this->getSession()->visit($this->locate_path('/')); 65 } 66 67 /** 68 * Reloads the current page. 69 * 70 * @Given /^I reload the page$/ 71 */ 72 public function reload() { 73 $this->getSession()->reload(); 74 } 75 76 /** 77 * Follows the page redirection. Use this step after any action that shows a message and waits for a redirection 78 * 79 * @Given /^I wait to be redirected$/ 80 */ 81 public function i_wait_to_be_redirected() { 82 83 // Xpath and processes based on core_renderer::redirect_message(), core_renderer::$metarefreshtag and 84 // moodle_page::$periodicrefreshdelay possible values. 85 if (!$metarefresh = $this->getSession()->getPage()->find('xpath', "//head/descendant::meta[@http-equiv='refresh']")) { 86 // We don't fail the scenario if no redirection with message is found to avoid race condition false failures. 87 return true; 88 } 89 90 // Wrapped in try & catch in case the redirection has already been executed. 91 try { 92 $content = $metarefresh->getAttribute('content'); 93 } catch (NoSuchElement $e) { 94 return true; 95 } catch (StaleElementReference $e) { 96 return true; 97 } 98 99 // Getting the refresh time and the url if present. 100 if (strstr($content, 'url') != false) { 101 102 list($waittime, $url) = explode(';', $content); 103 104 // Cleaning the URL value. 105 $url = trim(substr($url, strpos($url, 'http'))); 106 107 } else { 108 // Just wait then. 109 $waittime = $content; 110 } 111 112 113 // Wait until the URL change is executed. 114 if ($this->running_javascript()) { 115 $this->getSession()->wait($waittime * 1000, false); 116 117 } else if (!empty($url)) { 118 // We redirect directly as we can not wait for an automatic redirection. 119 $this->getSession()->getDriver()->getClient()->request('get', $url); 120 121 } else { 122 // Reload the page if no URL was provided. 123 $this->getSession()->getDriver()->reload(); 124 } 125 } 126 127 /** 128 * Switches to the specified iframe. 129 * 130 * @Given /^I switch to "(?P<iframe_name_string>(?:[^"]|\\")*)" iframe$/ 131 * @param string $iframename 132 */ 133 public function switch_to_iframe($iframename) { 134 135 // We spin to give time to the iframe to be loaded. 136 // Using extended timeout as we don't know about which 137 // kind of iframe will be loaded. 138 $this->spin( 139 function($context, $iframename) { 140 $context->getSession()->switchToIFrame($iframename); 141 142 // If no exception we are done. 143 return true; 144 }, 145 $iframename, 146 self::EXTENDED_TIMEOUT 147 ); 148 } 149 150 /** 151 * Switches to the main Moodle frame. 152 * 153 * @Given /^I switch to the main frame$/ 154 */ 155 public function switch_to_the_main_frame() { 156 $this->getSession()->switchToIFrame(); 157 } 158 159 /** 160 * Switches to the specified window. Useful when interacting with popup windows. 161 * 162 * @Given /^I switch to "(?P<window_name_string>(?:[^"]|\\")*)" window$/ 163 * @param string $windowname 164 */ 165 public function switch_to_window($windowname) { 166 // In Behat, some browsers (e.g. Chrome) are unable to switch to a 167 // window without a name, and by default the main browser window does 168 // not have a name. To work-around this, when we switch away from an 169 // unnamed window (presumably the main window) to some other named 170 // window, then we first set the main window name to a conventional 171 // value that we can later use this name to switch back. 172 $this->getSession()->evaluateScript( 173 'if (window.name == "") window.name = "' . self::MAIN_WINDOW_NAME . '"'); 174 175 $this->getSession()->switchToWindow($windowname); 176 } 177 178 /** 179 * Switches to the main Moodle window. Useful when you finish interacting with popup windows. 180 * 181 * @Given /^I switch to the main window$/ 182 */ 183 public function switch_to_the_main_window() { 184 $this->getSession()->switchToWindow(self::MAIN_WINDOW_NAME); 185 } 186 187 /** 188 * Accepts the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental. 189 * @Given /^I accept the currently displayed dialog$/ 190 */ 191 public function accept_currently_displayed_alert_dialog() { 192 $this->getSession()->getDriver()->getWebDriverSession()->accept_alert(); 193 } 194 195 /** 196 * Clicks link with specified id|title|alt|text. 197 * 198 * @When /^I follow "(?P<link_string>(?:[^"]|\\")*)"$/ 199 * @throws ElementNotFoundException Thrown by behat_base::find 200 * @param string $link 201 */ 202 public function click_link($link) { 203 204 $linknode = $this->find_link($link); 205 $this->ensure_node_is_visible($linknode); 206 $linknode->click(); 207 } 208 209 /** 210 * Waits X seconds. Required after an action that requires data from an AJAX request. 211 * 212 * @Then /^I wait "(?P<seconds_number>\d+)" seconds$/ 213 * @param int $seconds 214 */ 215 public function i_wait_seconds($seconds) { 216 217 if (!$this->running_javascript()) { 218 throw new DriverException('Waits are disabled in scenarios without Javascript support'); 219 } 220 221 $this->getSession()->wait($seconds * 1000, false); 222 } 223 224 /** 225 * Waits until the page is completely loaded. This step is auto-executed after every step. 226 * 227 * @Given /^I wait until the page is ready$/ 228 */ 229 public function wait_until_the_page_is_ready() { 230 231 if (!$this->running_javascript()) { 232 throw new DriverException('Waits are disabled in scenarios without Javascript support'); 233 } 234 235 $this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); 236 } 237 238 /** 239 * Waits until the provided element selector exists in the DOM 240 * 241 * Using the protected method as this method will be usually 242 * called by other methods which are not returning a set of 243 * steps and performs the actions directly, so it would not 244 * be executed if it returns another step. 245 246 * @Given /^I wait until "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" exists$/ 247 * @param string $element 248 * @param string $selector 249 * @return void 250 */ 251 public function wait_until_exists($element, $selectortype) { 252 $this->ensure_element_exists($element, $selectortype); 253 } 254 255 /** 256 * Waits until the provided element does not exist in the DOM 257 * 258 * Using the protected method as this method will be usually 259 * called by other methods which are not returning a set of 260 * steps and performs the actions directly, so it would not 261 * be executed if it returns another step. 262 263 * @Given /^I wait until "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" does not exist$/ 264 * @param string $element 265 * @param string $selector 266 * @return void 267 */ 268 public function wait_until_does_not_exists($element, $selectortype) { 269 $this->ensure_element_does_not_exist($element, $selectortype); 270 } 271 272 /** 273 * Generic mouse over action. Mouse over a element of the specified type. 274 * 275 * @When /^I hover "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/ 276 * @param string $element Element we look for 277 * @param string $selectortype The type of what we look for 278 */ 279 public function i_hover($element, $selectortype) { 280 281 // Gets the node based on the requested selector type and locator. 282 $node = $this->get_selected_node($selectortype, $element); 283 $node->mouseOver(); 284 } 285 286 /** 287 * Generic click action. Click on the element of the specified type. 288 * 289 * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/ 290 * @param string $element Element we look for 291 * @param string $selectortype The type of what we look for 292 */ 293 public function i_click_on($element, $selectortype) { 294 295 // Gets the node based on the requested selector type and locator. 296 $node = $this->get_selected_node($selectortype, $element); 297 $this->ensure_node_is_visible($node); 298 $node->click(); 299 } 300 301 /** 302 * Sets the focus and takes away the focus from an element, generating blur JS event. 303 * 304 * @When /^I take focus off "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/ 305 * @param string $element Element we look for 306 * @param string $selectortype The type of what we look for 307 */ 308 public function i_take_focus_off_field($element, $selectortype) { 309 if (!$this->running_javascript()) { 310 throw new ExpectationException('Can\'t take focus off from "' . $element . '" in non-js mode', $this->getSession()); 311 } 312 // Gets the node based on the requested selector type and locator. 313 $node = $this->get_selected_node($selectortype, $element); 314 $this->ensure_node_is_visible($node); 315 316 // Ensure element is focused before taking it off. 317 $node->focus(); 318 $node->blur(); 319 } 320 321 /** 322 * Clicks the specified element and confirms the expected dialogue. 323 * 324 * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" confirming the dialogue$/ 325 * @throws ElementNotFoundException Thrown by behat_base::find 326 * @param string $link 327 */ 328 public function i_click_on_confirming_the_dialogue($element, $selectortype) { 329 $this->i_click_on($element, $selectortype); 330 $this->accept_currently_displayed_alert_dialog(); 331 } 332 333 /** 334 * Click on the element of the specified type which is located inside the second element. 335 * 336 * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/ 337 * @param string $element Element we look for 338 * @param string $selectortype The type of what we look for 339 * @param string $nodeelement Element we look in 340 * @param string $nodeselectortype The type of selector where we look in 341 */ 342 public function i_click_on_in_the($element, $selectortype, $nodeelement, $nodeselectortype) { 343 344 $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement); 345 $this->ensure_node_is_visible($node); 346 $node->click(); 347 } 348 349 /** 350 * Drags and drops the specified element to the specified container. This step does not work in all the browsers, consider it experimental. 351 * 352 * The steps definitions calling this step as part of them should 353 * manage the wait times by themselves as the times and when the 354 * waits should be done depends on what is being dragged & dropper. 355 * 356 * @Given /^I drag "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" and I drop it in "(?P<container_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/ 357 * @param string $element 358 * @param string $selectortype 359 * @param string $containerelement 360 * @param string $containerselectortype 361 */ 362 public function i_drag_and_i_drop_it_in($element, $selectortype, $containerelement, $containerselectortype) { 363 364 list($sourceselector, $sourcelocator) = $this->transform_selector($selectortype, $element); 365 $sourcexpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($sourceselector, $sourcelocator); 366 367 list($containerselector, $containerlocator) = $this->transform_selector($containerselectortype, $containerelement); 368 $destinationxpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($containerselector, $containerlocator); 369 370 $this->getSession()->getDriver()->dragTo($sourcexpath, $destinationxpath); 371 } 372 373 /** 374 * Checks, that the specified element is visible. Only available in tests using Javascript. 375 * 376 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" should be visible$/ 377 * @throws ElementNotFoundException 378 * @throws ExpectationException 379 * @throws DriverException 380 * @param string $element 381 * @param string $selectortype 382 * @return void 383 */ 384 public function should_be_visible($element, $selectortype) { 385 386 if (!$this->running_javascript()) { 387 throw new DriverException('Visible checks are disabled in scenarios without Javascript support'); 388 } 389 390 $node = $this->get_selected_node($selectortype, $element); 391 if (!$node->isVisible()) { 392 throw new ExpectationException('"' . $element . '" "' . $selectortype . '" is not visible', $this->getSession()); 393 } 394 } 395 396 /** 397 * Checks, that the existing element is not visible. Only available in tests using Javascript. 398 * 399 * As a "not" method, it's performance could not be good, but in this 400 * case the performance is good because the element must exist, 401 * otherwise there would be a ElementNotFoundException, also here we are 402 * not spinning until the element is visible. 403 * 404 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" should not be visible$/ 405 * @throws ElementNotFoundException 406 * @throws ExpectationException 407 * @param string $element 408 * @param string $selectortype 409 * @return void 410 */ 411 public function should_not_be_visible($element, $selectortype) { 412 413 try { 414 $this->should_be_visible($element, $selectortype); 415 throw new ExpectationException('"' . $element . '" "' . $selectortype . '" is visible', $this->getSession()); 416 } catch (ExpectationException $e) { 417 // All as expected. 418 } 419 } 420 421 /** 422 * Checks, that the specified element is visible inside the specified container. Only available in tests using Javascript. 423 * 424 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" should be visible$/ 425 * @throws ElementNotFoundException 426 * @throws DriverException 427 * @throws ExpectationException 428 * @param string $element Element we look for 429 * @param string $selectortype The type of what we look for 430 * @param string $nodeelement Element we look in 431 * @param string $nodeselectortype The type of selector where we look in 432 */ 433 public function in_the_should_be_visible($element, $selectortype, $nodeelement, $nodeselectortype) { 434 435 if (!$this->running_javascript()) { 436 throw new DriverException('Visible checks are disabled in scenarios without Javascript support'); 437 } 438 439 $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement); 440 if (!$node->isVisible()) { 441 throw new ExpectationException( 442 '"' . $element . '" "' . $selectortype . '" in the "' . $nodeelement . '" "' . $nodeselectortype . '" is not visible', 443 $this->getSession() 444 ); 445 } 446 } 447 448 /** 449 * Checks, that the existing element is not visible inside the existing container. Only available in tests using Javascript. 450 * 451 * As a "not" method, it's performance could not be good, but in this 452 * case the performance is good because the element must exist, 453 * otherwise there would be a ElementNotFoundException, also here we are 454 * not spinning until the element is visible. 455 * 456 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" should not be visible$/ 457 * @throws ElementNotFoundException 458 * @throws ExpectationException 459 * @param string $element Element we look for 460 * @param string $selectortype The type of what we look for 461 * @param string $nodeelement Element we look in 462 * @param string $nodeselectortype The type of selector where we look in 463 */ 464 public function in_the_should_not_be_visible($element, $selectortype, $nodeelement, $nodeselectortype) { 465 466 try { 467 $this->in_the_should_be_visible($element, $selectortype, $nodeelement, $nodeselectortype); 468 throw new ExpectationException( 469 '"' . $element . '" "' . $selectortype . '" in the "' . $nodeelement . '" "' . $nodeselectortype . '" is visible', 470 $this->getSession() 471 ); 472 } catch (ExpectationException $e) { 473 // All as expected. 474 } 475 } 476 477 /** 478 * Checks, that page contains specified text. It also checks if the text is visible when running Javascript tests. 479 * 480 * @Then /^I should see "(?P<text_string>(?:[^"]|\\")*)"$/ 481 * @throws ExpectationException 482 * @param string $text 483 */ 484 public function assert_page_contains_text($text) { 485 486 // Looking for all the matching nodes without any other descendant matching the 487 // same xpath (we are using contains(., ....). 488 $xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text); 489 $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" . 490 "[count(descendant::*[contains(., $xpathliteral)]) = 0]"; 491 492 try { 493 $nodes = $this->find_all('xpath', $xpath); 494 } catch (ElementNotFoundException $e) { 495 throw new ExpectationException('"' . $text . '" text was not found in the page', $this->getSession()); 496 } 497 498 // If we are not running javascript we have enough with the 499 // element existing as we can't check if it is visible. 500 if (!$this->running_javascript()) { 501 return; 502 } 503 504 // We spin as we don't have enough checking that the element is there, we 505 // should also ensure that the element is visible. Using microsleep as this 506 // is a repeated step and global performance is important. 507 $this->spin( 508 function($context, $args) { 509 510 foreach ($args['nodes'] as $node) { 511 if ($node->isVisible()) { 512 return true; 513 } 514 } 515 516 // If non of the nodes is visible we loop again. 517 throw new ExpectationException('"' . $args['text'] . '" text was found but was not visible', $context->getSession()); 518 }, 519 array('nodes' => $nodes, 'text' => $text), 520 false, 521 false, 522 true 523 ); 524 525 } 526 527 /** 528 * Checks, that page doesn't contain specified text. When running Javascript tests it also considers that texts may be hidden. 529 * 530 * @Then /^I should not see "(?P<text_string>(?:[^"]|\\")*)"$/ 531 * @throws ExpectationException 532 * @param string $text 533 */ 534 public function assert_page_not_contains_text($text) { 535 536 // Looking for all the matching nodes without any other descendant matching the 537 // same xpath (we are using contains(., ....). 538 $xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text); 539 $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" . 540 "[count(descendant::*[contains(., $xpathliteral)]) = 0]"; 541 542 // We should wait a while to ensure that the page is not still loading elements. 543 // Waiting less than self::TIMEOUT as we already waited for the DOM to be ready and 544 // all JS to be executed. 545 try { 546 $nodes = $this->find_all('xpath', $xpath, false, false, self::REDUCED_TIMEOUT); 547 } catch (ElementNotFoundException $e) { 548 // All ok. 549 return; 550 } 551 552 // If we are not running javascript we have enough with the 553 // element existing as we can't check if it is hidden. 554 if (!$this->running_javascript()) { 555 throw new ExpectationException('"' . $text . '" text was found in the page', $this->getSession()); 556 } 557 558 // If the element is there we should be sure that it is not visible. 559 $this->spin( 560 function($context, $args) { 561 562 foreach ($args['nodes'] as $node) { 563 if ($node->isVisible()) { 564 throw new ExpectationException('"' . $args['text'] . '" text was found in the page', $context->getSession()); 565 } 566 } 567 568 // If non of the found nodes is visible we consider that the text is not visible. 569 return true; 570 }, 571 array('nodes' => $nodes, 'text' => $text), 572 self::REDUCED_TIMEOUT, 573 false, 574 true 575 ); 576 577 } 578 579 /** 580 * Checks, that the specified element contains the specified text. When running Javascript tests it also considers that texts may be hidden. 581 * 582 * @Then /^I should see "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/ 583 * @throws ElementNotFoundException 584 * @throws ExpectationException 585 * @param string $text 586 * @param string $element Element we look in. 587 * @param string $selectortype The type of element where we are looking in. 588 */ 589 public function assert_element_contains_text($text, $element, $selectortype) { 590 591 // Getting the container where the text should be found. 592 $container = $this->get_selected_node($selectortype, $element); 593 594 // Looking for all the matching nodes without any other descendant matching the 595 // same xpath (we are using contains(., ....). 596 $xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text); 597 $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" . 598 "[count(descendant::*[contains(., $xpathliteral)]) = 0]"; 599 600 // Wait until it finds the text inside the container, otherwise custom exception. 601 try { 602 $nodes = $this->find_all('xpath', $xpath, false, $container); 603 } catch (ElementNotFoundException $e) { 604 throw new ExpectationException('"' . $text . '" text was not found in the "' . $element . '" element', $this->getSession()); 605 } 606 607 // If we are not running javascript we have enough with the 608 // element existing as we can't check if it is visible. 609 if (!$this->running_javascript()) { 610 return; 611 } 612 613 // We also check the element visibility when running JS tests. Using microsleep as this 614 // is a repeated step and global performance is important. 615 $this->spin( 616 function($context, $args) { 617 618 foreach ($args['nodes'] as $node) { 619 if ($node->isVisible()) { 620 return true; 621 } 622 } 623 624 throw new ExpectationException('"' . $args['text'] . '" text was found in the "' . $args['element'] . '" element but was not visible', $context->getSession()); 625 }, 626 array('nodes' => $nodes, 'text' => $text, 'element' => $element), 627 false, 628 false, 629 true 630 ); 631 } 632 633 /** 634 * Checks, that the specified element does not contain the specified text. When running Javascript tests it also considers that texts may be hidden. 635 * 636 * @Then /^I should not see "(?P<text_string>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/ 637 * @throws ElementNotFoundException 638 * @throws ExpectationException 639 * @param string $text 640 * @param string $element Element we look in. 641 * @param string $selectortype The type of element where we are looking in. 642 */ 643 public function assert_element_not_contains_text($text, $element, $selectortype) { 644 645 // Getting the container where the text should be found. 646 $container = $this->get_selected_node($selectortype, $element); 647 648 // Looking for all the matching nodes without any other descendant matching the 649 // same xpath (we are using contains(., ....). 650 $xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text); 651 $xpath = "/descendant-or-self::*[contains(., $xpathliteral)]" . 652 "[count(descendant::*[contains(., $xpathliteral)]) = 0]"; 653 654 // We should wait a while to ensure that the page is not still loading elements. 655 // Giving preference to the reliability of the results rather than to the performance. 656 try { 657 $nodes = $this->find_all('xpath', $xpath, false, $container, self::REDUCED_TIMEOUT); 658 } catch (ElementNotFoundException $e) { 659 // All ok. 660 return; 661 } 662 663 // If we are not running javascript we have enough with the 664 // element not being found as we can't check if it is visible. 665 if (!$this->running_javascript()) { 666 throw new ExpectationException('"' . $text . '" text was found in the "' . $element . '" element', $this->getSession()); 667 } 668 669 // We need to ensure all the found nodes are hidden. 670 $this->spin( 671 function($context, $args) { 672 673 foreach ($args['nodes'] as $node) { 674 if ($node->isVisible()) { 675 throw new ExpectationException('"' . $args['text'] . '" text was found in the "' . $args['element'] . '" element', $context->getSession()); 676 } 677 } 678 679 // If all the found nodes are hidden we are happy. 680 return true; 681 }, 682 array('nodes' => $nodes, 'text' => $text, 'element' => $element), 683 self::REDUCED_TIMEOUT, 684 false, 685 true 686 ); 687 } 688 689 /** 690 * Checks, that the first specified element appears before the second one. 691 * 692 * @Given /^"(?P<preceding_element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" should appear before "(?P<following_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/ 693 * @throws ExpectationException 694 * @param string $preelement The locator of the preceding element 695 * @param string $preselectortype The locator of the preceding element 696 * @param string $postelement The locator of the latest element 697 * @param string $postselectortype The selector type of the latest element 698 */ 699 public function should_appear_before($preelement, $preselectortype, $postelement, $postselectortype) { 700 701 // We allow postselectortype as a non-text based selector. 702 list($preselector, $prelocator) = $this->transform_selector($preselectortype, $preelement); 703 list($postselector, $postlocator) = $this->transform_selector($postselectortype, $postelement); 704 705 $prexpath = $this->find($preselector, $prelocator)->getXpath(); 706 $postxpath = $this->find($postselector, $postlocator)->getXpath(); 707 708 // Using following xpath axe to find it. 709 $msg = '"'.$preelement.'" "'.$preselectortype.'" does not appear before "'.$postelement.'" "'.$postselectortype.'"'; 710 $xpath = $prexpath.'/following::*[contains(., '.$postxpath.')]'; 711 if (!$this->getSession()->getDriver()->find($xpath)) { 712 throw new ExpectationException($msg, $this->getSession()); 713 } 714 } 715 716 /** 717 * Checks, that the first specified element appears after the second one. 718 * 719 * @Given /^"(?P<following_element_string>(?:[^"]|\\")*)" "(?P<selector1_string>(?:[^"]|\\")*)" should appear after "(?P<preceding_element_string>(?:[^"]|\\")*)" "(?P<selector2_string>(?:[^"]|\\")*)"$/ 720 * @throws ExpectationException 721 * @param string $postelement The locator of the latest element 722 * @param string $postselectortype The selector type of the latest element 723 * @param string $preelement The locator of the preceding element 724 * @param string $preselectortype The locator of the preceding element 725 */ 726 public function should_appear_after($postelement, $postselectortype, $preelement, $preselectortype) { 727 728 // We allow postselectortype as a non-text based selector. 729 list($postselector, $postlocator) = $this->transform_selector($postselectortype, $postelement); 730 list($preselector, $prelocator) = $this->transform_selector($preselectortype, $preelement); 731 732 $postxpath = $this->find($postselector, $postlocator)->getXpath(); 733 $prexpath = $this->find($preselector, $prelocator)->getXpath(); 734 735 // Using preceding xpath axe to find it. 736 $msg = '"'.$postelement.'" "'.$postselectortype.'" does not appear after "'.$preelement.'" "'.$preselectortype.'"'; 737 $xpath = $postxpath.'/preceding::*[contains(., '.$prexpath.')]'; 738 if (!$this->getSession()->getDriver()->find($xpath)) { 739 throw new ExpectationException($msg, $this->getSession()); 740 } 741 } 742 743 /** 744 * Checks, that element of specified type is disabled. 745 * 746 * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be disabled$/ 747 * @throws ExpectationException Thrown by behat_base::find 748 * @param string $element Element we look in 749 * @param string $selectortype The type of element where we are looking in. 750 */ 751 public function the_element_should_be_disabled($element, $selectortype) { 752 753 // Transforming from steps definitions selector/locator format to Mink format and getting the NodeElement. 754 $node = $this->get_selected_node($selectortype, $element); 755 756 if (!$node->hasAttribute('disabled')) { 757 throw new ExpectationException('The element "' . $element . '" is not disabled', $this->getSession()); 758 } 759 } 760 761 /** 762 * Checks, that element of specified type is enabled. 763 * 764 * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be enabled$/ 765 * @throws ExpectationException Thrown by behat_base::find 766 * @param string $element Element we look on 767 * @param string $selectortype The type of where we look 768 */ 769 public function the_element_should_be_enabled($element, $selectortype) { 770 771 // Transforming from steps definitions selector/locator format to mink format and getting the NodeElement. 772 $node = $this->get_selected_node($selectortype, $element); 773 774 if ($node->hasAttribute('disabled')) { 775 throw new ExpectationException('The element "' . $element . '" is not enabled', $this->getSession()); 776 } 777 } 778 779 /** 780 * Checks the provided element and selector type are readonly on the current page. 781 * 782 * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should be readonly$/ 783 * @throws ExpectationException Thrown by behat_base::find 784 * @param string $element Element we look in 785 * @param string $selectortype The type of element where we are looking in. 786 */ 787 public function the_element_should_be_readonly($element, $selectortype) { 788 // Transforming from steps definitions selector/locator format to Mink format and getting the NodeElement. 789 $node = $this->get_selected_node($selectortype, $element); 790 791 if (!$node->hasAttribute('readonly')) { 792 throw new ExpectationException('The element "' . $element . '" is not readonly', $this->getSession()); 793 } 794 } 795 796 /** 797 * Checks the provided element and selector type are not readonly on the current page. 798 * 799 * @Then /^the "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not be readonly$/ 800 * @throws ExpectationException Thrown by behat_base::find 801 * @param string $element Element we look in 802 * @param string $selectortype The type of element where we are looking in. 803 */ 804 public function the_element_should_not_be_readonly($element, $selectortype) { 805 // Transforming from steps definitions selector/locator format to Mink format and getting the NodeElement. 806 $node = $this->get_selected_node($selectortype, $element); 807 808 if ($node->hasAttribute('readonly')) { 809 throw new ExpectationException('The element "' . $element . '" is readonly', $this->getSession()); 810 } 811 } 812 813 /** 814 * Checks the provided element and selector type exists in the current page. 815 * 816 * This step is for advanced users, use it if you don't find anything else suitable for what you need. 817 * 818 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should exist$/ 819 * @throws ElementNotFoundException Thrown by behat_base::find 820 * @param string $element The locator of the specified selector 821 * @param string $selectortype The selector type 822 */ 823 public function should_exist($element, $selectortype) { 824 825 // Getting Mink selector and locator. 826 list($selector, $locator) = $this->transform_selector($selectortype, $element); 827 828 // Will throw an ElementNotFoundException if it does not exist. 829 $this->find($selector, $locator); 830 } 831 832 /** 833 * Checks that the provided element and selector type not exists in the current page. 834 * 835 * This step is for advanced users, use it if you don't find anything else suitable for what you need. 836 * 837 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not exist$/ 838 * @throws ExpectationException 839 * @param string $element The locator of the specified selector 840 * @param string $selectortype The selector type 841 */ 842 public function should_not_exist($element, $selectortype) { 843 844 // Getting Mink selector and locator. 845 list($selector, $locator) = $this->transform_selector($selectortype, $element); 846 847 try { 848 849 // Using directly the spin method as we want a reduced timeout but there is no 850 // need for a 0.1 seconds interval because in the optimistic case we will timeout. 851 $params = array('selector' => $selector, 'locator' => $locator); 852 // The exception does not really matter as we will catch it and will never "explode". 853 $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $element); 854 855 // If all goes good it will throw an ElementNotFoundExceptionn that we will catch. 856 $this->spin( 857 function($context, $args) { 858 return $context->getSession()->getPage()->findAll($args['selector'], $args['locator']); 859 }, 860 $params, 861 self::REDUCED_TIMEOUT, 862 $exception, 863 false 864 ); 865 866 throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the current page', $this->getSession()); 867 } catch (ElementNotFoundException $e) { 868 // It passes. 869 return; 870 } 871 } 872 873 /** 874 * This step triggers cron like a user would do going to admin/cron.php. 875 * 876 * @Given /^I trigger cron$/ 877 */ 878 public function i_trigger_cron() { 879 $this->getSession()->visit($this->locate_path('/admin/cron.php')); 880 } 881 882 /** 883 * Checks that an element and selector type exists in another element and selector type on the current page. 884 * 885 * This step is for advanced users, use it if you don't find anything else suitable for what you need. 886 * 887 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should exist in the "(?P<element2_string>(?:[^"]|\\")*)" "(?P<selector2_string>[^"]*)"$/ 888 * @throws ElementNotFoundException Thrown by behat_base::find 889 * @param string $element The locator of the specified selector 890 * @param string $selectortype The selector type 891 * @param string $containerelement The container selector type 892 * @param string $containerselectortype The container locator 893 */ 894 public function should_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) { 895 // Get the container node. 896 $containernode = $this->get_selected_node($containerselectortype, $containerelement); 897 898 list($selector, $locator) = $this->transform_selector($selectortype, $element); 899 900 // Specific exception giving info about where can't we find the element. 901 $locatorexceptionmsg = $element . '" in the "' . $containerelement. '" "' . $containerselectortype. '"'; 902 $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $locatorexceptionmsg); 903 904 // Looks for the requested node inside the container node. 905 $this->find($selector, $locator, $exception, $containernode); 906 } 907 908 /** 909 * Checks that an element and selector type does not exist in another element and selector type on the current page. 910 * 911 * This step is for advanced users, use it if you don't find anything else suitable for what you need. 912 * 913 * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not exist in the "(?P<element2_string>(?:[^"]|\\")*)" "(?P<selector2_string>[^"]*)"$/ 914 * @throws ExpectationException 915 * @param string $element The locator of the specified selector 916 * @param string $selectortype The selector type 917 * @param string $containerelement The container selector type 918 * @param string $containerselectortype The container locator 919 */ 920 public function should_not_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) { 921 922 // Get the container node; here we throw an exception 923 // if the container node does not exist. 924 $containernode = $this->get_selected_node($containerselectortype, $containerelement); 925 926 list($selector, $locator) = $this->transform_selector($selectortype, $element); 927 928 // Will throw an ElementNotFoundException if it does not exist, but, actually 929 // it should not exist, so we try & catch it. 930 try { 931 // Would be better to use a 1 second sleep because the element should not be there, 932 // but we would need to duplicate the whole find_all() logic to do it, the benefit of 933 // changing to 1 second sleep is not significant. 934 $this->find($selector, $locator, false, $containernode, self::REDUCED_TIMEOUT); 935 throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the "' . 936 $containerelement . '" "' . $containerselectortype . '"', $this->getSession()); 937 } catch (ElementNotFoundException $e) { 938 // It passes. 939 return; 940 } 941 } 942 943 /** 944 * Change browser window size small: 640x480, medium: 1024x768, large: 2560x1600, custom: widthxheight 945 * 946 * Example: I change window size to "small" or I change window size to "1024x768" 947 * 948 * @throws ExpectationException 949 * @Then /^I change window size to "([^"](small|medium|large|\d+x\d+))"$/ 950 * @param string $windowsize size of the window (small|medium|large|wxh). 951 */ 952 public function i_change_window_size_to($windowsize) { 953 $this->resize_window($windowsize); 954 } 955 956 /** 957 * Checks whether there is an attribute on the given element that contains the specified text. 958 * 959 * @Then /^the "(?P<attribute_string>[^"]*)" attribute of "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should contain "(?P<text_string>(?:[^"]|\\")*)"$/ 960 * @throws ExpectationException 961 * @param string $attribute Name of attribute 962 * @param string $element The locator of the specified selector 963 * @param string $selectortype The selector type 964 * @param string $text Expected substring 965 */ 966 public function the_attribute_of_should_contain($attribute, $element, $selectortype, $text) { 967 // Get the container node (exception if it doesn't exist). 968 $containernode = $this->get_selected_node($selectortype, $element); 969 $value = $containernode->getAttribute($attribute); 970 if ($value == null) { 971 throw new ExpectationException('The attribute "' . $attribute. '" does not exist', 972 $this->getSession()); 973 } else if (strpos($value, $text) === false) { 974 throw new ExpectationException('The attribute "' . $attribute . 975 '" does not contain "' . $text . '" (actual value: "' . $value . '")', 976 $this->getSession()); 977 } 978 } 979 980 /** 981 * Checks that the attribute on the given element does not contain the specified text. 982 * 983 * @Then /^the "(?P<attribute_string>[^"]*)" attribute of "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" should not contain "(?P<text_string>(?:[^"]|\\")*)"$/ 984 * @throws ExpectationException 985 * @param string $attribute Name of attribute 986 * @param string $element The locator of the specified selector 987 * @param string $selectortype The selector type 988 * @param string $text Expected substring 989 */ 990 public function the_attribute_of_should_not_contain($attribute, $element, $selectortype, $text) { 991 // Get the container node (exception if it doesn't exist). 992 $containernode = $this->get_selected_node($selectortype, $element); 993 $value = $containernode->getAttribute($attribute); 994 if ($value == null) { 995 throw new ExpectationException('The attribute "' . $attribute. '" does not exist', 996 $this->getSession()); 997 } else if (strpos($value, $text) !== false) { 998 throw new ExpectationException('The attribute "' . $attribute . 999 '" contains "' . $text . '" (value: "' . $value . '")', 1000 $this->getSession()); 1001 } 1002 } 1003 1004 /** 1005 * Checks the provided value exists in specific row/column of table. 1006 * 1007 * @Then /^"(?P<row_string>[^"]*)" row "(?P<column_string>[^"]*)" column of "(?P<table_string>[^"]*)" table should contain "(?P<value_string>[^"]*)"$/ 1008 * @throws ElementNotFoundException 1009 * @param string $row row text which will be looked in. 1010 * @param string $column column text to search (or numeric value for the column position) 1011 * @param string $table table id/class/caption 1012 * @param string $value text to check. 1013 */ 1014 public function row_column_of_table_should_contain($row, $column, $table, $value) { 1015 $tablenode = $this->get_selected_node('table', $table); 1016 $tablexpath = $tablenode->getXpath(); 1017 1018 $rowliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($row); 1019 $valueliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($value); 1020 $columnliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($column); 1021 1022 if (preg_match('/^-?(\d+)-?$/', $column, $columnasnumber)) { 1023 // Column indicated as a number, just use it as position of the column. 1024 $columnpositionxpath = "/child::*[position() = {$columnasnumber[1]}]"; 1025 } else { 1026 // Header can be in thead or tbody (first row), following xpath should work. 1027 $theadheaderxpath = "thead/tr[1]/th[(normalize-space(.)=" . $columnliteral . " or a[normalize-space(text())=" . 1028 $columnliteral . "])]"; 1029 $tbodyheaderxpath = "tbody/tr[1]/td[(normalize-space(.)=" . $columnliteral . " or a[normalize-space(text())=" . 1030 $columnliteral . "])]"; 1031 1032 // Check if column exists. 1033 $columnheaderxpath = $tablexpath . "[" . $theadheaderxpath . " | " . $tbodyheaderxpath . "]"; 1034 $columnheader = $this->getSession()->getDriver()->find($columnheaderxpath); 1035 if (empty($columnheader)) { 1036 $columnexceptionmsg = $column . '" in table "' . $table . '"'; 1037 throw new ElementNotFoundException($this->getSession(), "\n$columnheaderxpath\n\n".'Column', null, $columnexceptionmsg); 1038 } 1039 // Following conditions were considered before finding column count. 1040 // 1. Table header can be in thead/tr/th or tbody/tr/td[1]. 1041 // 2. First column can have th (Gradebook -> user report), so having lenient sibling check. 1042 $columnpositionxpath = "/child::*[position() = count(" . $tablexpath . "/" . $theadheaderxpath . 1043 "/preceding-sibling::*) + 1]"; 1044 } 1045 1046 // Check if value exists in specific row/column. 1047 // Get row xpath. 1048 $rowxpath = $tablexpath."/tbody/tr[th[normalize-space(.)=" . $rowliteral . "] | td[normalize-space(.)=" . $rowliteral . "]]"; 1049 1050 $columnvaluexpath = $rowxpath . $columnpositionxpath . "[contains(normalize-space(.)," . $valueliteral . ")]"; 1051 1052 // Looks for the requested node inside the container node. 1053 $coumnnode = $this->getSession()->getDriver()->find($columnvaluexpath); 1054 if (empty($coumnnode)) { 1055 $locatorexceptionmsg = $value . '" in "' . $row . '" row with column "' . $column; 1056 throw new ElementNotFoundException($this->getSession(), "\n$columnvaluexpath\n\n".'Column value', null, $locatorexceptionmsg); 1057 } 1058 } 1059 1060 /** 1061 * Checks the provided value should not exist in specific row/column of table. 1062 * 1063 * @Then /^"(?P<row_string>[^"]*)" row "(?P<column_string>[^"]*)" column of "(?P<table_string>[^"]*)" table should not contain "(?P<value_string>[^"]*)"$/ 1064 * @throws ElementNotFoundException 1065 * @param string $row row text which will be looked in. 1066 * @param string $column column text to search 1067 * @param string $table table id/class/caption 1068 * @param string $value text to check. 1069 */ 1070 public function row_column_of_table_should_not_contain($row, $column, $table, $value) { 1071 try { 1072 $this->row_column_of_table_should_contain($row, $column, $table, $value); 1073 // Throw exception if found. 1074 throw new ExpectationException( 1075 '"' . $column . '" with value "' . $value . '" is present in "' . $row . '" row for table "' . $table . '"', 1076 $this->getSession() 1077 ); 1078 } catch (ElementNotFoundException $e) { 1079 // Table row/column doesn't contain this value. Nothing to do. 1080 return; 1081 } 1082 } 1083 1084 /** 1085 * Checks that the provided value exist in table. 1086 * More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps. 1087 * 1088 * First row may contain column headers or numeric indexes of the columns 1089 * (syntax -1- is also considered to be column index). Column indexes are 1090 * useful in case of multirow headers and/or presence of cells with colspan. 1091 * 1092 * @Then /^the following should exist in the "(?P<table_string>[^"]*)" table:$/ 1093 * @throws ExpectationException 1094 * @param string $table name of table 1095 * @param TableNode $data table with first row as header and following values 1096 * | Header 1 | Header 2 | Header 3 | 1097 * | Value 1 | Value 2 | Value 3| 1098 */ 1099 public function following_should_exist_in_the_table($table, TableNode $data) { 1100 $datahash = $data->getHash(); 1101 1102 foreach ($datahash as $row) { 1103 $firstcell = null; 1104 foreach ($row as $column => $value) { 1105 if ($firstcell === null) { 1106 $firstcell = $value; 1107 } else { 1108 $this->row_column_of_table_should_contain($firstcell, $column, $table, $value); 1109 } 1110 } 1111 } 1112 } 1113 1114 /** 1115 * Checks that the provided value exist in table. 1116 * More info in http://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps. 1117 * 1118 * @Then /^the following should not exist in the "(?P<table_string>[^"]*)" table:$/ 1119 * @throws ExpectationException 1120 * @param string $table name of table 1121 * @param TableNode $data table with first row as header and following values 1122 * | Header 1 | Header 2 | Header 3 | 1123 * | Value 1 | Value 2 | Value 3| 1124 */ 1125 public function following_should_not_exist_in_the_table($table, TableNode $data) { 1126 $datahash = $data->getHash(); 1127 1128 foreach ($datahash as $value) { 1129 $row = array_shift($value); 1130 foreach ($value as $column => $value) { 1131 try { 1132 $this->row_column_of_table_should_contain($row, $column, $table, $value); 1133 // Throw exception if found. 1134 throw new ExpectationException('"' . $column . '" with value "' . $value . '" is present in "' . 1135 $row . '" row for table "' . $table . '"', $this->getSession() 1136 ); 1137 } catch (ElementNotFoundException $e) { 1138 // Table row/column doesn't contain this value. Nothing to do. 1139 continue; 1140 } 1141 } 1142 } 1143 } 1144 1145 /** 1146 * Given the text of a link, download the linked file and return the contents. 1147 * 1148 * This is a helper method used by {@link following_should_download_bytes()} 1149 * and {@link following_should_download_between_and_bytes()} 1150 * 1151 * @param string $link the text of the link. 1152 * @return string the content of the downloaded file. 1153 */ 1154 protected function download_file_from_link($link) { 1155 // Find the link. 1156 $linknode = $this->find_link($link); 1157 $this->ensure_node_is_visible($linknode); 1158 1159 // Get the href and check it. 1160 $url = $linknode->getAttribute('href'); 1161 if (!$url) { 1162 throw new ExpectationException('Download link does not have href attribute', 1163 $this->getSession()); 1164 } 1165 if (!preg_match('~^https?://~', $url)) { 1166 throw new ExpectationException('Download link not an absolute URL: ' . $url, 1167 $this->getSession()); 1168 } 1169 1170 // Download the URL and check the size. 1171 $session = $this->getSession()->getCookie('MoodleSession'); 1172 return download_file_content($url, array('Cookie' => 'MoodleSession=' . $session)); 1173 } 1174 1175 /** 1176 * Downloads the file from a link on the page and checks the size. 1177 * 1178 * Only works if the link has an href attribute. Javascript downloads are 1179 * not supported. Currently, the href must be an absolute URL. 1180 * 1181 * @Then /^following "(?P<link_string>[^"]*)" should download "(?P<expected_bytes>\d+)" bytes$/ 1182 * @throws ExpectationException 1183 * @param string $link the text of the link. 1184 * @param number $expectedsize the expected file size in bytes. 1185 */ 1186 public function following_should_download_bytes($link, $expectedsize) { 1187 $result = $this->download_file_from_link($link); 1188 $actualsize = (int)strlen($result); 1189 if ($actualsize !== (int)$expectedsize) { 1190 throw new ExpectationException('Downloaded data was ' . $actualsize . 1191 ' bytes, expecting ' . $expectedsize, $this->getSession()); 1192 } 1193 } 1194 1195 /** 1196 * Downloads the file from a link on the page and checks the size is in a given range. 1197 * 1198 * Only works if the link has an href attribute. Javascript downloads are 1199 * not supported. Currently, the href must be an absolute URL. 1200 * 1201 * The range includes the endpoints. That is, a 10 byte file in considered to 1202 * be between "5" and "10" bytes, and between "10" and "20" bytes. 1203 * 1204 * @Then /^following "(?P<link_string>[^"]*)" should download between "(?P<min_bytes>\d+)" and "(?P<max_bytes>\d+)" bytes$/ 1205 * @throws ExpectationException 1206 * @param string $link the text of the link. 1207 * @param number $minexpectedsize the minimum expected file size in bytes. 1208 * @param number $maxexpectedsize the maximum expected file size in bytes. 1209 */ 1210 public function following_should_download_between_and_bytes($link, $minexpectedsize, $maxexpectedsize) { 1211 // If the minimum is greater than the maximum then swap the values. 1212 if ((int)$minexpectedsize > (int)$maxexpectedsize) { 1213 list($minexpectedsize, $maxexpectedsize) = array($maxexpectedsize, $minexpectedsize); 1214 } 1215 1216 $result = $this->download_file_from_link($link); 1217 $actualsize = (int)strlen($result); 1218 if ($actualsize < $minexpectedsize || $actualsize > $maxexpectedsize) { 1219 throw new ExpectationException('Downloaded data was ' . $actualsize . 1220 ' bytes, expecting between ' . $minexpectedsize . ' and ' . 1221 $maxexpectedsize, $this->getSession()); 1222 } 1223 } 1224 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |