MDL-41030 Behat: Add support for waiting for javascript

This is so that phantomjs (which runs faster than selenium) can pass the tests.
This commit is contained in:
Damyon Wiese
2013-12-06 12:13:39 +08:00
committed by David Monllao
parent 5d2b67228c
commit 6e2c417c1f
4 changed files with 124 additions and 34 deletions
+25 -1
View File
@@ -60,6 +60,30 @@ class behat_forms extends behat_base {
$buttonnode->press();
}
/**
* Try a few times to set a field value as it may not be visible yet (TinyMCE).
*
* @param string $field
* @param string $value
*/
public function set_field_value($field, $value) {
$lastexception = null;
// Spin on this - certain fields, e.g. text editors (I'm looking at you TinyMCE) load slowly and randomly.
$retries = 5;
while ($retries > 0) {
try {
$field->set_value($value);
return;
} catch (Exception $e) {
usleep(100000);
$retries--;
$lastexception = $e;
}
}
// If we timeout - throw the last exception.
throw $lastexception;
}
/**
* Fills a moodle form with field/value data.
*
@@ -84,7 +108,7 @@ class behat_forms extends behat_base {
$field = behat_field_manager::get_form_field($fieldnode, $this->getSession());
// Delegates to the field class.
$field->set_value($value);
$this->set_field_value($field, $value);
}
}
+20 -30
View File
@@ -222,42 +222,32 @@ class behat_hooks extends behat_base {
}
/**
* Checks that all DOM is ready.
* Wait for JS to comlete.
*
* Executed only when running against a real browser.
*
* @AfterStep @javascript
* @BeforeStep @javascript
*/
public function after_step_javascript($event) {
// If it doesn't have definition or it fails there is no need to check it.
if ($event->getResult() != StepEvent::PASSED ||
!$event->hasDefinition()) {
return;
}
// Wait until the page is ready.
// We are already checking that we use a JS browser, this could
// change in case we use another JS driver.
try {
// Safari and Internet Explorer requires time between steps,
// otherwise Selenium tries to click in the previous page's DOM.
if ($this->getSession()->getDriver()->getBrowserName() == 'safari' ||
$this->getSession()->getDriver()->getBrowserName() == 'internet explorer') {
$this->getSession()->wait(self::TIMEOUT * 1000, false);
} else {
// With other browsers we just wait for the DOM ready.
$this->getSession()->wait(self::TIMEOUT * 1000, '(document.readyState === "complete")');
public function before_step_javascript($event) {
$lastpending = '';
// Wait for all pending JS to complete (max 10 seconds).
for ($i = 0; $i < 100; $i++) {
$pending = '';
try {
$pending = ($this->getSession()->evaluateScript('return (M && M.util && M.util.pending_js) ? M.util.pending_js.join(":") : "not loaded";'));
} catch (NoSuchWindow $nsw) {
// No javascript is running if there is no window right?
$pending = '';
}
} catch (NoSuchWindow $e) {
// If we were interacting with a popup window it will not exists after closing it.
} catch (UnknownError $e) {
// Custom exception to provide more feedback about possible solutions.
$this->throw_unknown_exception($e);
if ($pending === '') {
return;
}
$lastpending = $pending;
// 0.1 seconds.
usleep(100000);
}
// Timeout waiting for JS to complete.
// We could throw an exception here - as this is a likely indicator of slow JS or JS errors.
}
/**