Merge branch 'wip-mdl-53381-m29' of https://github.com/rajeshtaneja/moodle into MOODLE_29_STABLE
This commit is contained in:
@@ -47,34 +47,15 @@ class behat_auth extends behat_base {
|
||||
* @Given /^I log in as "(?P<username_string>(?:[^"]|\\")*)"$/
|
||||
*/
|
||||
public function i_log_in_as($username) {
|
||||
// Visit login page.
|
||||
$this->getSession()->visit($this->locate_path('login/index.php'));
|
||||
|
||||
// Running this step using the API rather than a chained step because
|
||||
// we need to see if the 'Log in' link is available or we need to click
|
||||
// the dropdown to expand the navigation bar before.
|
||||
$this->getSession()->visit($this->locate_path('/'));
|
||||
// Enter username and password.
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('Username', $this->escape($username)));
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('Password', $this->escape($username)));
|
||||
|
||||
// Generic steps (we will prefix them later expanding the navigation dropdown if necessary).
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('login') . '" "link" in the ".logininfo" "css_element"'),
|
||||
new Given('I set the field "' . get_string('username') . '" to "' . $this->escape($username) . '"'),
|
||||
new Given('I set the field "' . get_string('password') . '" to "'. $this->escape($username) . '"'),
|
||||
new Given('I press "' . get_string('login') . '"')
|
||||
);
|
||||
|
||||
// If Javascript is disabled we have enough with these steps.
|
||||
if (!$this->running_javascript()) {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
// Wait for the homepage to be ready.
|
||||
$this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
|
||||
|
||||
// If it is needed, it expands the navigation bar with the 'Log in' link.
|
||||
if ($clicknavbar = $this->get_expand_navbar_step()) {
|
||||
array_unshift($steps, $clicknavbar);
|
||||
}
|
||||
|
||||
return $steps;
|
||||
// Press log in button, no need to check for exceptions as it will checked after this step execution.
|
||||
$this->execute('behat_forms::press_button', get_string('login'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,53 +64,16 @@ class behat_auth extends behat_base {
|
||||
* @Given /^I log out$/
|
||||
*/
|
||||
public function i_log_out() {
|
||||
|
||||
$steps = array(new When('I follow "' . get_string('logout') . '"'));
|
||||
|
||||
// No need to check anything else if we run without JS.
|
||||
if (!$this->running_javascript()) {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
// There is no longer any need to worry about whether the navigation
|
||||
// bar needs to be expanded; user_menu now lives outside the
|
||||
// hamburger.
|
||||
|
||||
// However, the user menu *always* needs to be expanded.
|
||||
$xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
|
||||
array_unshift($steps, new When('I click on "'.$xpath.'" "xpath_element"'));
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a step to open the navigation bar if it is needed.
|
||||
*
|
||||
* The top log in and log out links are hidden when middle or small
|
||||
* size windows (or devices) are used. This step returns a step definition
|
||||
* clicking to expand the navbar if it is hidden.
|
||||
*
|
||||
* @return Given|bool A step definition or false if there is no need to show the navbar.
|
||||
*/
|
||||
protected function get_expand_navbar_step() {
|
||||
|
||||
// Checking if we need to click the navbar button to show the navigation menu, it
|
||||
// is hidden by default when using clean theme and a medium or small screen size.
|
||||
|
||||
// The DOM and the JS should be all ready and loaded. Running without spinning
|
||||
// as this is a widely used step and we can not spend time here trying to see
|
||||
// a DOM node that is not always there (at the moment clean is not even the
|
||||
// default theme...).
|
||||
$navbuttonjs = "return (
|
||||
Y.one('.btn-navbar') &&
|
||||
Y.one('.btn-navbar').getComputedStyle('display') !== 'none'
|
||||
)";
|
||||
|
||||
// Adding an extra click we need to show the 'Log in' link.
|
||||
if (!$this->getSession()->getDriver()->evaluateScript($navbuttonjs)) {
|
||||
return false;
|
||||
// However, the user menu *always* needs to be expanded. if running JS.
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
|
||||
$this->execute('behat_general::i_click_on', array($xpath, "xpath_element"));
|
||||
}
|
||||
|
||||
return new Given('I click on ".btn-navbar" "css_element"');
|
||||
// No need to check for exceptions as it will checked after this step execution.
|
||||
$this->execute('behat_general::click_link', get_string('logout'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -637,4 +637,166 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
|
||||
}
|
||||
$this->getSession()->getDriver()->resizeWindow($width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for all the JS to be loaded.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws NoSuchWindow
|
||||
* @throws UnknownError
|
||||
* @return bool True or false depending whether all the JS is loaded or not.
|
||||
*/
|
||||
public function wait_for_pending_js() {
|
||||
// Waiting for JS is only valid for JS scenarios.
|
||||
if (!$this->running_javascript()) {
|
||||
return;
|
||||
}
|
||||
// We don't use behat_base::spin() here as we don't want to end up with an exception
|
||||
// if the page & JSs don't finish loading properly.
|
||||
for ($i = 0; $i < self::EXTENDED_TIMEOUT * 10; $i++) {
|
||||
$pending = '';
|
||||
try {
|
||||
$jscode = '
|
||||
return function() {
|
||||
if (typeof M === "undefined") {
|
||||
if (document.readyState === "complete") {
|
||||
return "";
|
||||
} else {
|
||||
return "incomplete";
|
||||
}
|
||||
} else if (' . self::PAGE_READY_JS . ') {
|
||||
return "";
|
||||
} else if (typeof M.util !== "undefined") {
|
||||
return M.util.pending_js.join(":");
|
||||
} else {
|
||||
return "incomplete";
|
||||
}
|
||||
}();';
|
||||
$pending = $this->getSession()->evaluateScript($jscode);
|
||||
} catch (NoSuchWindow $nsw) {
|
||||
// We catch an exception here, in case we just closed the window we were interacting with.
|
||||
// No javascript is running if there is no window right?
|
||||
$pending = '';
|
||||
} catch (UnknownError $e) {
|
||||
// M is not defined when the window or the frame don't exist anymore.
|
||||
if (strstr($e->getMessage(), 'M is not defined') != false) {
|
||||
$pending = '';
|
||||
}
|
||||
}
|
||||
// If there are no pending JS we stop waiting.
|
||||
if ($pending === '') {
|
||||
return true;
|
||||
}
|
||||
// 0.1 seconds.
|
||||
usleep(100000);
|
||||
}
|
||||
// Timeout waiting for JS to complete. It will be catched and forwarded to behat_hooks::i_look_for_exceptions().
|
||||
// It is unlikely that Javascript code of a page or an AJAX request needs more than self::EXTENDED_TIMEOUT seconds
|
||||
// to be loaded, although when pages contains Javascript errors M.util.js_complete() can not be executed, so the
|
||||
// number of JS pending code and JS completed code will not match and we will reach this point.
|
||||
throw new \Exception('Javascript code and/or AJAX requests are not ready after ' . self::EXTENDED_TIMEOUT .
|
||||
' seconds. There is a Javascript error or the code is extremely slow.');
|
||||
}
|
||||
/**
|
||||
* Internal step definition to find exceptions, debugging() messages and PHP debug messages.
|
||||
*
|
||||
* Part of behat_hooks class as is part of the testing framework, is auto-executed
|
||||
* after each step so no features will splicitly use it.
|
||||
*
|
||||
* @throws Exception Unknown type, depending on what we caught in the hook or basic \Exception.
|
||||
* @see Moodle\BehatExtension\Tester\MoodleStepTester
|
||||
*/
|
||||
public function look_for_exceptions() {
|
||||
// Wrap in try in case we were interacting with a closed window.
|
||||
try {
|
||||
// Exceptions.
|
||||
$exceptionsxpath = "//div[@data-rel='fatalerror']";
|
||||
// Debugging messages.
|
||||
$debuggingxpath = "//div[@data-rel='debugging']";
|
||||
// PHP debug messages.
|
||||
$phperrorxpath = "//div[@data-rel='phpdebugmessage']";
|
||||
// Any other backtrace.
|
||||
$othersxpath = "(//*[contains(., ': call to ')])[1]";
|
||||
$xpaths = array($exceptionsxpath, $debuggingxpath, $phperrorxpath, $othersxpath);
|
||||
$joinedxpath = implode(' | ', $xpaths);
|
||||
// Joined xpath expression. Most of the time there will be no exceptions, so this pre-check
|
||||
// is faster than to send the 4 xpath queries for each step.
|
||||
if (!$this->getSession()->getDriver()->find($joinedxpath)) {
|
||||
return;
|
||||
}
|
||||
// Exceptions.
|
||||
if ($errormsg = $this->getSession()->getPage()->find('xpath', $exceptionsxpath)) {
|
||||
// Getting the debugging info and the backtrace.
|
||||
$errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.alert-error');
|
||||
// If errorinfoboxes is empty, try find notifytiny (original) class.
|
||||
if (empty($errorinfoboxes)) {
|
||||
$errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.notifytiny');
|
||||
}
|
||||
$errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml()) . "\n" .
|
||||
$this->get_debug_text($errorinfoboxes[1]->getHtml());
|
||||
$msg = "Moodle exception: " . $errormsg->getText() . "\n" . $errorinfo;
|
||||
throw new \Exception(html_entity_decode($msg));
|
||||
}
|
||||
// Debugging messages.
|
||||
if ($debuggingmessages = $this->getSession()->getPage()->findAll('xpath', $debuggingxpath)) {
|
||||
$msgs = array();
|
||||
foreach ($debuggingmessages as $debuggingmessage) {
|
||||
$msgs[] = $this->get_debug_text($debuggingmessage->getHtml());
|
||||
}
|
||||
$msg = "debugging() message/s found:\n" . implode("\n", $msgs);
|
||||
throw new \Exception(html_entity_decode($msg));
|
||||
}
|
||||
// PHP debug messages.
|
||||
if ($phpmessages = $this->getSession()->getPage()->findAll('xpath', $phperrorxpath)) {
|
||||
$msgs = array();
|
||||
foreach ($phpmessages as $phpmessage) {
|
||||
$msgs[] = $this->get_debug_text($phpmessage->getHtml());
|
||||
}
|
||||
$msg = "PHP debug message/s found:\n" . implode("\n", $msgs);
|
||||
throw new \Exception(html_entity_decode($msg));
|
||||
}
|
||||
// Any other backtrace.
|
||||
// First looking through xpath as it is faster than get and parse the whole page contents,
|
||||
// we get the contents and look for matches once we found something to suspect that there is a backtrace.
|
||||
if ($this->getSession()->getDriver()->find($othersxpath)) {
|
||||
$backtracespattern = '/(line [0-9]* of [^:]*: call to [\->&;:a-zA-Z_\x7f-\xff][\->&;:a-zA-Z0-9_\x7f-\xff]*)/';
|
||||
if (preg_match_all($backtracespattern, $this->getSession()->getPage()->getContent(), $backtraces)) {
|
||||
$msgs = array();
|
||||
foreach ($backtraces[0] as $backtrace) {
|
||||
$msgs[] = $backtrace . '()';
|
||||
}
|
||||
$msg = "Other backtraces found:\n" . implode("\n", $msgs);
|
||||
throw new \Exception(htmlentities($msg));
|
||||
}
|
||||
}
|
||||
} catch (NoSuchWindow $e) {
|
||||
// If we were interacting with a popup window it will not exists after closing it.
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Helper function to execute api in a given context.
|
||||
*
|
||||
* @param string $contextapi context in which api is defined.
|
||||
* @param array $params list of params to pass.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function execute($contextapi, $params = array()) {
|
||||
if (!is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
|
||||
// Get required context and execute the api.
|
||||
$contextapi = explode("::", $contextapi);
|
||||
$context = behat_context_helper::get($contextapi[0]);
|
||||
call_user_func_array(array($context, $contextapi[1]), $params);
|
||||
|
||||
// NOTE: Wait for pending js and look for exception are not optional, as this might lead to unexpected results.
|
||||
// So don't make them optional for performance reasons.
|
||||
|
||||
// Wait for pending js.
|
||||
$this->wait_for_pending_js();
|
||||
|
||||
// Look for exceptions.
|
||||
$this->look_for_exceptions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,62 +489,6 @@ class behat_hooks extends behat_base {
|
||||
return array($dir, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for all the JS to be loaded.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws NoSuchWindow
|
||||
* @throws UnknownError
|
||||
* @return bool True or false depending whether all the JS is loaded or not.
|
||||
*/
|
||||
protected function wait_for_pending_js() {
|
||||
|
||||
// We don't use behat_base::spin() here as we don't want to end up with an exception
|
||||
// if the page & JSs don't finish loading properly.
|
||||
for ($i = 0; $i < self::EXTENDED_TIMEOUT * 10; $i++) {
|
||||
$pending = '';
|
||||
try {
|
||||
$jscode =
|
||||
'if (typeof M === "undefined") {
|
||||
if (document.readyState === "complete") {
|
||||
return "";
|
||||
} else {
|
||||
return "incomplete";
|
||||
}
|
||||
} else if (' . self::PAGE_READY_JS . ') {
|
||||
return "";
|
||||
} else {
|
||||
return M.util.pending_js.join(":");
|
||||
}';
|
||||
$pending = $this->getSession()->evaluateScript($jscode);
|
||||
} catch (NoSuchWindow $nsw) {
|
||||
// We catch an exception here, in case we just closed the window we were interacting with.
|
||||
// No javascript is running if there is no window right?
|
||||
$pending = '';
|
||||
} catch (UnknownError $e) {
|
||||
// M is not defined when the window or the frame don't exist anymore.
|
||||
if (strstr($e->getMessage(), 'M is not defined') != false) {
|
||||
$pending = '';
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no pending JS we stop waiting.
|
||||
if ($pending === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0.1 seconds.
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
// Timeout waiting for JS to complete. It will be catched and forwarded to behat_hooks::i_look_for_exceptions().
|
||||
// It is unlikely that Javascript code of a page or an AJAX request needs more than self::EXTENDED_TIMEOUT seconds
|
||||
// to be loaded, although when pages contains Javascript errors M.util.js_complete() can not be executed, so the
|
||||
// number of JS pending code and JS completed code will not match and we will reach this point.
|
||||
throw new \Exception('Javascript code and/or AJAX requests are not ready after ' . self::EXTENDED_TIMEOUT .
|
||||
' seconds. There is a Javascript error or the code is extremely slow.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal step definition to find exceptions, debugging() messages and PHP debug messages.
|
||||
*
|
||||
@@ -562,82 +506,9 @@ class behat_hooks extends behat_base {
|
||||
throw self::$currentstepexception;
|
||||
}
|
||||
|
||||
// Wrap in try in case we were interacting with a closed window.
|
||||
try {
|
||||
// Look for exceptions displayed on page.
|
||||
$this->look_for_exceptions();
|
||||
|
||||
// Exceptions.
|
||||
$exceptionsxpath = "//div[@data-rel='fatalerror']";
|
||||
// Debugging messages.
|
||||
$debuggingxpath = "//div[@data-rel='debugging']";
|
||||
// PHP debug messages.
|
||||
$phperrorxpath = "//div[@data-rel='phpdebugmessage']";
|
||||
// Any other backtrace.
|
||||
$othersxpath = "(//*[contains(., ': call to ')])[1]";
|
||||
|
||||
$xpaths = array($exceptionsxpath, $debuggingxpath, $phperrorxpath, $othersxpath);
|
||||
$joinedxpath = implode(' | ', $xpaths);
|
||||
|
||||
// Joined xpath expression. Most of the time there will be no exceptions, so this pre-check
|
||||
// is faster than to send the 4 xpath queries for each step.
|
||||
if (!$this->getSession()->getDriver()->find($joinedxpath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exceptions.
|
||||
if ($errormsg = $this->getSession()->getPage()->find('xpath', $exceptionsxpath)) {
|
||||
|
||||
// Getting the debugging info and the backtrace.
|
||||
$errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.alert-error');
|
||||
// If errorinfoboxes is empty, try find notifytiny (original) class.
|
||||
if (empty($errorinfoboxes)) {
|
||||
$errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.notifytiny');
|
||||
}
|
||||
$errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml()) . "\n" .
|
||||
$this->get_debug_text($errorinfoboxes[1]->getHtml());
|
||||
|
||||
$msg = "Moodle exception: " . $errormsg->getText() . "\n" . $errorinfo;
|
||||
throw new \Exception(html_entity_decode($msg));
|
||||
}
|
||||
|
||||
// Debugging messages.
|
||||
if ($debuggingmessages = $this->getSession()->getPage()->findAll('xpath', $debuggingxpath)) {
|
||||
$msgs = array();
|
||||
foreach ($debuggingmessages as $debuggingmessage) {
|
||||
$msgs[] = $this->get_debug_text($debuggingmessage->getHtml());
|
||||
}
|
||||
$msg = "debugging() message/s found:\n" . implode("\n", $msgs);
|
||||
throw new \Exception(html_entity_decode($msg));
|
||||
}
|
||||
|
||||
// PHP debug messages.
|
||||
if ($phpmessages = $this->getSession()->getPage()->findAll('xpath', $phperrorxpath)) {
|
||||
|
||||
$msgs = array();
|
||||
foreach ($phpmessages as $phpmessage) {
|
||||
$msgs[] = $this->get_debug_text($phpmessage->getHtml());
|
||||
}
|
||||
$msg = "PHP debug message/s found:\n" . implode("\n", $msgs);
|
||||
throw new \Exception(html_entity_decode($msg));
|
||||
}
|
||||
|
||||
// Any other backtrace.
|
||||
// First looking through xpath as it is faster than get and parse the whole page contents,
|
||||
// we get the contents and look for matches once we found something to suspect that there is a backtrace.
|
||||
if ($this->getSession()->getDriver()->find($othersxpath)) {
|
||||
$backtracespattern = '/(line [0-9]* of [^:]*: call to [\->&;:a-zA-Z_\x7f-\xff][\->&;:a-zA-Z0-9_\x7f-\xff]*)/';
|
||||
if (preg_match_all($backtracespattern, $this->getSession()->getPage()->getContent(), $backtraces)) {
|
||||
$msgs = array();
|
||||
foreach ($backtraces[0] as $backtrace) {
|
||||
$msgs[] = $backtrace . '()';
|
||||
}
|
||||
$msg = "Other backtraces found:\n" . implode("\n", $msgs);
|
||||
throw new \Exception(htmlentities($msg));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (NoSuchWindow $e) {
|
||||
// If we were interacting with a popup window it will not exists after closing it.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user