nextcloud/tests/acceptance/features/core/ElementWrapper.php

360 lines
13 KiB
PHP
Raw Normal View History

Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
<?php
/**
*
* @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* Wrapper to automatically handle failed commands on Mink elements.
*
* Commands executed on Mink elements may fail for several reasons. The
* ElementWrapper frees the caller of the commands from handling the most common
* reasons of failure.
*
* StaleElementReference exceptions are thrown when the command is executed on
* an element that is no longer attached to the DOM. This can happen even in
* a chained call like "$actor->find($locator)->click()"; in the milliseconds
* between finding the element and clicking it the element could have been
* removed from the page (for example, if a previous interaction with the page
* started an asynchronous update of the DOM). Every command executed through
* the ElementWrapper is guarded against StaleElementReference exceptions; if
* the element is stale it is found again using the same parameters to find it
* in the first place.
*
* NoSuchElement exceptions are sometimes thrown instead of
* StaleElementReference exceptions. This can happen when the Selenium2 driver
* for Mink performs an action on an element through the WebDriver session
* instead of directly through the WebDriver element. In that case, if the
* element with the given ID does not exist, a NoSuchElement exception would be
* thrown instead of a StaleElementReference exception, so those cases are
* handled like StaleElementReference exceptions.
*
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
* ElementNotVisible exceptions are thrown when the command requires the element
* to be visible but the element is not. Finding an element only guarantees that
* (at that time) the element is attached to the DOM, but it does not provide
* any guarantee regarding its visibility. Due to that, a call like
* "$actor->find($locator)->click()" can fail if the element was hidden and
* meant to be made visible by a previous interaction with the page, but that
* interaction triggered an asynchronous update that was not finished when the
* click command is executed. All commands executed through the ElementWrapper
* that require the element to be visible are guarded against ElementNotVisible
* exceptions; if the element is not visible it is waited for it to be visible
* up to the timeout set to find it.
*
* MoveTargetOutOfBounds exceptions are sometimes thrown instead of
* ElementNotVisible exceptions. This can happen when the Selenium2 driver for
* Mink moves the cursor on an element using the "moveto" method of the
* WebDriver session, for example, before clicking on an element. In that case,
* if the element is not visible, "moveto" would throw a MoveTargetOutOfBounds
* exception instead of an ElementNotVisible exception, so those cases are
* handled like ElementNotVisible exceptions.
*
* ElementNotInteractable exceptions are thrown in Selenium 3 when the command
* needs to interact with an element but that is not possible. This could be a
* transitive situation (for example, due to an animation), so the command is
* executed again after a small timeout.
*
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
* Despite the automatic handling it is possible for the commands to throw those
* exceptions when they are executed again; this class does not handle cases
* like an element becoming stale several times in a row (uncommon) or an
* element not becoming visible before the timeout expires (which would mean
* that the timeout is too short or that the test has to, indeed, fail). In a
* similar way, MoveTargetOutOfBounds exceptions would be thrown again if
* originally they were thrown because the element was visible but "out of
* reach". ElementNotInteractable exceptions would be thrown again if it is not
* possible to interact yet with the element after the wait (which could mean
* that the test has to, indeed, fail, although it could mean too that the
* automatic handling needs to be improved).
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
*
* If needed, automatically handling failed commands can be disabled calling
* "doNotHandleFailedCommands()"; as it returns the ElementWrapper it can be
* chained with the command to execute (but note that automatically handling
* failed commands will still be disabled if further commands are executed on
* the ElementWrapper).
*/
class ElementWrapper {
/**
* @var ElementFinder
*/
private $elementFinder;
/**
* @var \Behat\Mink\Element\Element
*/
private $element;
/**
* @param boolean
*/
private $handleFailedCommands;
/**
* Creates a new ElementWrapper.
*
* The wrapped element is found in the constructor itself using the
* ElementFinder.
*
* @param ElementFinder $elementFinder the command object to find the
* wrapped element.
* @throws NoSuchElementException if the element, or its ancestor, can not
* be found.
*/
public function __construct(ElementFinder $elementFinder) {
$this->elementFinder = $elementFinder;
$this->element = $elementFinder->find();
$this->handleFailedCommands = true;
}
/**
* Returns the raw Mink element.
*
* @return \Behat\Mink\Element\Element the wrapped element.
*/
public function getWrappedElement() {
return $this->element;
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
}
/**
* Prevents the automatic handling of failed commands.
*
* @return ElementWrapper this ElementWrapper.
*/
public function doNotHandleFailedCommands() {
$this->handleFailedCommands = false;
return $this;
}
/**
* Returns whether the wrapped element is visible or not.
*
* @return bool true if the wrapped element is visible, false otherwise.
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
*/
public function isVisible() {
$commandCallback = function () {
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
return $this->element->isVisible();
};
return $this->executeCommand($commandCallback, "visibility could not be got");
}
/**
* Returns whether the wrapped element is checked or not.
*
* @return bool true if the wrapped element is checked, false otherwise.
*/
public function isChecked() {
$commandCallback = function () {
return $this->element->isChecked();
};
return $this->executeCommand($commandCallback, "check state could not be got");
}
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
/**
* Returns the text of the wrapped element.
*
* If the wrapped element is not visible the returned text is an empty
* string.
*
* @return string the text of the wrapped element, or an empty string if it
* is not visible.
*/
public function getText() {
$commandCallback = function () {
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
return $this->element->getText();
};
return $this->executeCommand($commandCallback, "text could not be got");
}
/**
* Returns the value of the wrapped element.
*
* The value can be got even if the wrapped element is not visible.
*
* @return string the value of the wrapped element.
*/
public function getValue() {
$commandCallback = function () {
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
return $this->element->getValue();
};
return $this->executeCommand($commandCallback, "value could not be got");
}
/**
* Sets the given value on the wrapped element.
*
* If automatically waits for the wrapped element to be visible (up to the
* timeout set when finding it).
*
* @param string $value the value to set.
*/
public function setValue($value) {
$commandCallback = function () use ($value) {
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
$this->element->setValue($value);
};
$this->executeCommandOnVisibleElement($commandCallback, "value could not be set");
}
/**
* Clicks on the wrapped element.
*
* If automatically waits for the wrapped element to be visible (up to the
* timeout set when finding it).
*/
public function click() {
$commandCallback = function () {
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
$this->element->click();
};
$this->executeCommandOnVisibleElement($commandCallback, "could not be clicked");
}
/**
* Check the wrapped element.
*
* If automatically waits for the wrapped element to be visible (up to the
* timeout set when finding it).
*/
public function check() {
$commandCallback = function () {
$this->element->check();
};
$this->executeCommand($commandCallback, "could not be checked");
}
/**
* uncheck the wrapped element.
*
* If automatically waits for the wrapped element to be visible (up to the
* timeout set when finding it).
*/
public function uncheck() {
$commandCallback = function () {
$this->element->uncheck();
};
$this->executeCommand($commandCallback, "could not be unchecked");
}
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
/**
* Executes the given command.
*
* If a StaleElementReference or a NoSuchElement exception is thrown the
* wrapped element is found again and, then, the command is executed again.
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
*
* @param \Closure $commandCallback the command to execute.
* @param string $errorMessage an error message that describes the failed
* command (appended to the description of the element).
*/
private function executeCommand(\Closure $commandCallback, $errorMessage) {
if (!$this->handleFailedCommands) {
return $commandCallback();
}
try {
return $commandCallback();
} catch (\WebDriver\Exception\StaleElementReference $exception) {
$this->printFailedCommandMessage($exception, $errorMessage);
} catch (\WebDriver\Exception\NoSuchElement $exception) {
$this->printFailedCommandMessage($exception, $errorMessage);
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
}
$this->element = $this->elementFinder->find();
return $commandCallback();
}
/**
* Executes the given command on a visible element.
*
* If a StaleElementReference or a NoSuchElement exception is thrown the
* wrapped element is found again and, then, the command is executed again.
* If an ElementNotVisible or a MoveTargetOutOfBounds exception is thrown it
* is waited for the wrapped element to be visible and, then, the command is
* executed again.
* If an ElementNotInteractable exception is thrown it is also waited for
* the wrapped element to be visible. It is very likely that the element was
* visible already, but it is not possible to easily check if the element
* can be interacted with, retrying will be only useful if it was a
* transitive situation that resolves itself with a wait (for example, due
* to an animation) and waiting for the element to be visible will always
* start with a wait.
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
*
* @param \Closure $commandCallback the command to execute.
* @param string $errorMessage an error message that describes the failed
* command (appended to the description of the element).
*/
private function executeCommandOnVisibleElement(\Closure $commandCallback, $errorMessage) {
if (!$this->handleFailedCommands) {
return $commandCallback();
}
try {
return $this->executeCommand($commandCallback, $errorMessage);
} catch (\WebDriver\Exception\ElementNotVisible $exception) {
$this->printFailedCommandMessage($exception, $errorMessage);
} catch (\WebDriver\Exception\MoveTargetOutOfBounds $exception) {
$this->printFailedCommandMessage($exception, $errorMessage);
} catch (\Exception $exception) {
// The "ElementNotInteractable" exception is not available yet in
// the current "instaclick/php-webdriver" version, so it is thrown
// as a generic exception with a specific message.
if (stripos($exception->getMessage(), "element not interactable") === false) {
throw $exception;
}
$this->printFailedCommandMessage($exception, $errorMessage);
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
}
$this->waitForElementToBeVisible();
return $commandCallback();
}
/**
* Prints information about the failed command.
*
* @param \Exception exception the exception thrown by the command.
* @param string $errorMessage an error message that describes the failed
* command (appended to the description of the locator of the element).
*/
private function printFailedCommandMessage(\Exception $exception, $errorMessage) {
echo $this->elementFinder->getDescription() . " " . $errorMessage . "\n";
echo "Exception message: " . $exception->getMessage() . "\n";
echo "Trying again\n";
}
/**
* Waits for the wrapped element to be visible.
*
* This method waits up to the timeout used when finding the wrapped
* element; therefore, it may return when the element is still not visible.
*
* @return boolean true if the element is visible after the wait, false
* otherwise.
*/
private function waitForElementToBeVisible() {
$isVisibleCallback = function () {
Add automatic handling of common command failures of Mink elements Commands executed on Mink elements may fail for several reasons. ElementWrapper is introduced to automatically handle some of those situations, like StaleElementReference exceptions and ElementNotVisible exceptions. StaleElementReference exceptions are thrown when the command is executed on an element that is no longer attached to the DOM. When that happens the ElementWrapper finds again the element and executes the command again on the new element. ElementNotVisible exceptions are thrown when the command requires the element to be visible but the element is not. When that happens the ElementWrapper waits for the element to be visible before executing the command again. These changes are totally compatible with the current acceptance tests. They just make the tests more robust, but they do not change their behaviour. In fact, this should minimize some of the sporadic failures in the acceptance tests caused by their concurrent nature with respect to the web browser executing the commands. However, the ElementWrapper is not a silver bullet; it handles the most common situations, but it does not handle every possible scenario. For example, the acceptance tests would still fail sporadically if an element can become staled several times in a row (uncommon) or if it does not become visible before the timeout expires (which could still happen in a loaded system even if the components under test work right, but obviously it is not possible to wait indefinitely for them). Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-05-05 23:54:20 +03:00
return $this->isVisible();
};
$timeout = $this->elementFinder->getTimeout();
$timeoutStep = $this->elementFinder->getTimeoutStep();
return Utils::waitFor($isVisibleCallback, $timeout, $timeoutStep);
}
}