Skip to content

Commit

Permalink
MDL-46891 behat: Move wait in behat_base so it can be used easily
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajesh Taneja committed Mar 11, 2016
1 parent 86055d1 commit 0729830
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 64 deletions.
64 changes: 63 additions & 1 deletion lib/behat/behat_base.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ protected function find_all($selector, $locator, $exception = false, $node = fal
if (!$exception) {

// With named selectors we can be more specific.
if (($selector == 'named_exact') || ($selector == 'named_partial')){
if (($selector == 'named_exact') || ($selector == 'named_partial')) {
$exceptiontype = $locator[0];
$exceptionlocator = $locator[1];

Expand Down Expand Up @@ -651,4 +651,66 @@ protected function resize_window($windowsize) {
}
$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 {
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.');
}
}
58 changes: 0 additions & 58 deletions lib/tests/behat/behat_hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -489,64 +489,6 @@ protected function get_faildump_filename(AfterStepScope $scope, $filetype) {
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 =
'return function() {
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.
*
Expand Down
20 changes: 15 additions & 5 deletions mod/choice/tests/behat/behat_mod_choice.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,24 @@ public function I_choose_option_from_activity($option, $choiceactivity) {
* @return array
*/
public function I_choose_options_from_activity($option, $choiceactivity) {
// Escaping again the strings as backslashes have been removed by the automatic transformation.
$return = array(new Given('I follow "' . $this->escape($choiceactivity) . '"'));
// Get Behat general and forms contexts.
$behatgeneral = behat_context_helper::get('behat_general');
$behatforms = behat_context_helper::get('behat_forms');

// Go to choice activity.
$behatgeneral->click_link($this->escape($choiceactivity));

// Wait for page to be loaded.
$this->wait_for_pending_js();

// Set all options.
$options = explode('","', trim($option, '"'));
foreach ($options as $option) {
$return[] = new Given('I set the field "' . $this->escape($option) . '" to "1"');
$behatforms->i_set_the_field_to($this->escape($option), '1');
}
$return[] = new Given('I press "' . get_string('savemychoice', 'choice') . '"');
return $return;

// Save choice.
$behatforms->press_button(get_string('savemychoice', 'choice'));
}

}

0 comments on commit 0729830

Please sign in to comment.