Merge branch 'MDL-43837_master' of git://github.com/dmonllao/moodle

This commit is contained in:
Damyon Wiese 2014-02-24 16:56:05 +08:00
commit 237243db02
3 changed files with 108 additions and 27 deletions

View File

@ -52,6 +52,15 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
*/
class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
/**
* Small timeout.
*
* A reduced timeout for cases where self::TIMEOUT is too much
* and a simple $this->getSession()->getPage()->find() could not
* be enough.
*/
const REDUCED_TIMEOUT = 2;
/**
* The timeout for each Behat step (load page, wait for an element to load...).
*/
@ -88,12 +97,13 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
* @param mixed $locator It depends on the $selector, can be the xpath, a name, a css locator...
* @param Exception $exception Otherwise we throw exception with generic info
* @param NodeElement $node Spins around certain DOM node instead of the whole page
* @param int $timeout Forces a specific time out (in seconds).
* @return NodeElement
*/
protected function find($selector, $locator, $exception = false, $node = false) {
protected function find($selector, $locator, $exception = false, $node = false, $timeout = false) {
// Returns the first match.
$items = $this->find_all($selector, $locator, $exception, $node);
$items = $this->find_all($selector, $locator, $exception, $node, $timeout);
return count($items) ? reset($items) : null;
}
@ -107,9 +117,10 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
* @param mixed $locator It depends on the $selector, can be the xpath, a name, a css locator...
* @param Exception $exception Otherwise we throw expcetion with generic info
* @param NodeElement $node Spins around certain DOM node instead of the whole page
* @param int $timeout Forces a specific time out (in seconds). If 0 is provided the default timeout will be applied.
* @return array NodeElements list
*/
protected function find_all($selector, $locator, $exception = false, $node = false) {
protected function find_all($selector, $locator, $exception = false, $node = false, $timeout = false) {
// Generic info.
if (!$exception) {
@ -138,6 +149,17 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
$params['node'] = $node;
}
// How much we will be waiting for the element to appear.
if (!$timeout) {
$timeout = self::TIMEOUT;
$microsleep = false;
} else {
// Spinning each 0.1 seconds if the timeout was forced as we understand
// that is a special case and is good to refine the performance as much
// as possible.
$microsleep = true;
}
// Waits for the node to appear if it exists, otherwise will timeout and throw the provided exception.
return $this->spin(
function($context, $args) {
@ -170,8 +192,9 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
return $context->getSession()->getDriver()->find(implode('|', $unions));
},
$params,
self::TIMEOUT,
$exception
$timeout,
$exception,
$microsleep
);
}
@ -569,7 +592,7 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
// If there are no editors we don't need to wait.
try {
$this->find('css', '.mceEditor');
$this->find('css', '.mceEditor', false, false, self::REDUCED_TIMEOUT);
} catch (ElementNotFoundException $e) {
return;
}

View File

@ -110,18 +110,20 @@ class behat_forms extends behat_base {
// We ensure that all the editors are loaded and we can interact with them.
$this->ensure_editors_are_loaded();
// behat_base::find() throws an exception if there are no elements, we should not fail a test because of this.
// We already know that we waited for the DOM and the JS to be loaded, even the editor
// so, we will use the reduced timeout as it is a common task and we should save time.
try {
// Expand fieldsets link.
$collapseexpandlink = $this->find('xpath', "//div[@class='collapsible-actions']" .
$xpath = "//div[@class='collapsible-actions']" .
"/descendant::a[contains(concat(' ', @class, ' '), ' collapseexpand ')]" .
"[not(contains(concat(' ', @class, ' '), ' collapse-all '))]"
);
"[not(contains(concat(' ', @class, ' '), ' collapse-all '))]";
$collapseexpandlink = $this->find('xpath', $xpath, false, false, self::REDUCED_TIMEOUT);
$collapseexpandlink->click();
} catch (ElementNotFoundException $e) {
// We continue if there are not expandable fields.
// The behat_base::find() method throws an exception if there are no elements,
// we should not fail a test because of this. We continue if there are not expandable fields.
}
// Different try & catch as we can have expanded fieldsets with advanced fields on them.
@ -132,7 +134,9 @@ class behat_forms extends behat_base {
"[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]";
// We don't wait here as we already waited when getting the expand fieldsets links.
$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath);
if (!$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath)) {
return;
}
// Funny thing about this, with findAll() we specify a pattern and each element matching the pattern is added to the array
// with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath

View File

@ -346,10 +346,12 @@ class behat_general extends behat_base {
}
/**
* Checks, that the specified element is not visible. Only available in tests using Javascript.
* Checks, that the existing element is not visible. Only available in tests using Javascript.
*
* As a "not" method, it's performance is not specially good as we should ensure that the element
* have time to appear.
* As a "not" method, it's performance could not be good, but in this
* case the performance is good because the element must exist,
* otherwise there would be a ElementNotFoundException, also here we are
* not spinning until the element is visible.
*
* @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" should not be visible$/
* @throws ElementNotFoundException
@ -396,7 +398,12 @@ class behat_general extends behat_base {
}
/**
* Checks, that the specified element is not visible inside the specified container. Only available in tests using Javascript.
* Checks, that the existing element is not visible inside the existing container. Only available in tests using Javascript.
*
* As a "not" method, it's performance could not be good, but in this
* case the performance is good because the element must exist,
* otherwise there would be a ElementNotFoundException, also here we are
* not spinning until the element is visible.
*
* @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" should not be visible$/
* @throws ElementNotFoundException
@ -447,7 +454,8 @@ class behat_general extends behat_base {
}
// We spin as we don't have enough checking that the element is there, we
// should also ensure that the element is visible.
// should also ensure that the element is visible. Using microsleep as this
// is a repeated step and global performance is important.
$this->spin(
function($context, $args) {
@ -460,7 +468,10 @@ class behat_general extends behat_base {
// If non of the nodes is visible we loop again.
throw new ExpectationException('"' . $args['text'] . '" text was found but was not visible', $context->getSession());
},
array('nodes' => $nodes, 'text' => $text)
array('nodes' => $nodes, 'text' => $text),
false,
false,
true
);
}
@ -481,9 +492,10 @@ class behat_general extends behat_base {
"[count(descendant::*[contains(., $xpathliteral)]) = 0]";
// We should wait a while to ensure that the page is not still loading elements.
// Giving preference to the reliability of the results rather than to the performance.
// Waiting less than self::TIMEOUT as we already waited for the DOM to be ready and
// all JS to be executed.
try {
$nodes = $this->find_all('xpath', $xpath);
$nodes = $this->find_all('xpath', $xpath, false, false, self::REDUCED_TIMEOUT);
} catch (ElementNotFoundException $e) {
// All ok.
return;
@ -508,7 +520,10 @@ class behat_general extends behat_base {
// If non of the found nodes is visible we consider that the text is not visible.
return true;
},
array('nodes' => $nodes, 'text' => $text)
array('nodes' => $nodes, 'text' => $text),
self::REDUCED_TIMEOUT,
false,
true
);
}
@ -547,7 +562,8 @@ class behat_general extends behat_base {
return;
}
// We also check the element visibility when running JS tests.
// We also check the element visibility when running JS tests. Using microsleep as this
// is a repeated step and global performance is important.
$this->spin(
function($context, $args) {
@ -559,7 +575,10 @@ class behat_general extends behat_base {
throw new ExpectationException('"' . $args['text'] . '" text was found in the "' . $args['element'] . '" element but was not visible', $context->getSession());
},
array('nodes' => $nodes, 'text' => $text, 'element' => $element)
array('nodes' => $nodes, 'text' => $text, 'element' => $element),
false,
false,
true
);
}
@ -587,7 +606,7 @@ class behat_general extends behat_base {
// We should wait a while to ensure that the page is not still loading elements.
// Giving preference to the reliability of the results rather than to the performance.
try {
$nodes = $this->find_all('xpath', $xpath, false, $container);
$nodes = $this->find_all('xpath', $xpath, false, $container, self::REDUCED_TIMEOUT);
} catch (ElementNotFoundException $e) {
// All ok.
return;
@ -612,7 +631,10 @@ class behat_general extends behat_base {
// If all the found nodes are hidden we are happy.
return true;
},
array('nodes' => $nodes, 'text' => $text, 'element' => $element)
array('nodes' => $nodes, 'text' => $text, 'element' => $element),
self::REDUCED_TIMEOUT,
false,
true
);
}
@ -771,8 +793,28 @@ class behat_general extends behat_base {
*/
public function should_not_exists($element, $selectortype) {
// Getting Mink selector and locator.
list($selector, $locator) = $this->transform_selector($selectortype, $element);
try {
$this->should_exists($element, $selectortype);
// Using directly the spin method as we want a reduced timeout but there is no
// need for a 0.1 seconds interval because in the optimistic case we will timeout.
$params = array('selector' => $selector, 'locator' => $locator);
// The exception does not really matter as we will catch it and will never "explode".
$exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $element);
// If all goes good it will throw an ElementNotFoundExceptionn that we will catch.
$this->spin(
function($context, $args) {
return $context->getSession()->getPage()->findAll($args['selector'], $args['locator']);
},
$params,
false,
$exception,
self::REDUCED_TIMEOUT
);
throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the current page', $this->getSession());
} catch (ElementNotFoundException $e) {
// It passes.
@ -828,8 +870,20 @@ class behat_general extends behat_base {
* @param string $containerselectortype The container locator
*/
public function should_not_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) {
// Get the container node; here we throw an exception
// if the container node does not exist.
$containernode = $this->get_selected_node($containerselectortype, $containerelement);
list($selector, $locator) = $this->transform_selector($selectortype, $element);
// Will throw an ElementNotFoundException if it does not exist, but, actually
// it should not exists, so we try & catch it.
try {
$this->should_exist_in_the($element, $selectortype, $containerelement, $containerselectortype);
// Would be better to use a 1 second sleep because the element should not be there,
// but we would need to duplicate the whole find_all() logic to do it, the benefit of
// changing to 1 second sleep is not significant.
$this->find($selector, $locator, false, $containernode, self::REDUCED_TIMEOUT);
throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the "' .
$containerelement . '" "' . $containerselectortype . '"', $this->getSession());
} catch (ElementNotFoundException $e) {