Reputation: 44325
I am using python-selenium
to run automated tests. In the complex non-public environment these tests are running in I found something what I would label as a bug in selenium.
Basically what I try to do is to find some element in the DOM, when it becomes clickable, and then click it. The code is as follows:
....
what = (By.XPATH, '//button/span[contains(text(), "Load")]')
element = WebDriverWait(bspdriver.webdriver, 60).\
until(EC.element_to_be_clickable(what))
element.click()
....
However, the click
method fails almost immediately with the following error message:
ElementClickInterceptedException: Message: Element <button class="ivu-btn ivu-btn-primary ivu-btn-long ivu-btn-small" type="button"> is not clickable at point (1193.3332901000977,522) because another element <div class="ivu-modal-wrap vertical-center-modal circuit-loading-modal"> obscures it
I though I am waiting for the element to be clickable! I assumed that EC.element_to_be_clickable
means exactly that. But it does not. Is that a bug in selenium?
A workaround is the following code:
mustend = time.time() + 60
while time.time() < mustend:
try:
WebDriverWait(bspdriver.webdriver, 60).\
until(EC.element_to_be_clickable(what)).click()
break
except (TimeoutException, NoSuchElementException,
StaleElementReferenceException,
ElementClickInterceptedException) as e:
time.sleep(1.0)
which does not look so nice to me. Is there a way to improve the code? Is there a bug in selenium? If so, I can report it...
Used packages:
Full error message:
....
> element.click()
selenium/test_pair_recording.py:66:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py:80: in click
self._execute(Command.CLICK_ELEMENT)
../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py:501: in _execute
return self._parent.execute(command, params)
../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py:311: in execute
self.error_handler.check_response(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x7fe69694fd90>
response = {'status': 400, 'value': '{"value":{"error":"element click intercepted","message":"Element <button class=\"ivu-btn ivu...gate@chrome://marionette/content/listener.js:414:13\nclickElement@chrome://marionette/content/listener.js:1220:5\n"}}'}
def check_response(self, response):
"""
Checks that a JSON response from the WebDriver does not have an error.
:Args:
- response - The JSON response from the WebDriver server as a dictionary
object.
:Raises: If the response contains an error message.
"""
status = response.get('status', None)
if status is None or status == ErrorCode.SUCCESS:
return
value = None
message = response.get("message", "")
screen = response.get("screen", "")
stacktrace = None
if isinstance(status, int):
value_json = response.get('value', None)
if value_json and isinstance(value_json, basestring):
import json
try:
value = json.loads(value_json)
if len(value.keys()) == 1:
value = value['value']
status = value.get('error', None)
if status is None:
status = value["status"]
message = value["value"]
if not isinstance(message, basestring):
value = message
message = message.get('message')
else:
message = value.get('message', None)
except ValueError:
pass
exception_class = ErrorInResponseException
if status in ErrorCode.NO_SUCH_ELEMENT:
exception_class = NoSuchElementException
elif status in ErrorCode.NO_SUCH_FRAME:
exception_class = NoSuchFrameException
elif status in ErrorCode.NO_SUCH_WINDOW:
exception_class = NoSuchWindowException
elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
exception_class = StaleElementReferenceException
elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
exception_class = ElementNotVisibleException
elif status in ErrorCode.INVALID_ELEMENT_STATE:
exception_class = InvalidElementStateException
elif status in ErrorCode.INVALID_SELECTOR \
or status in ErrorCode.INVALID_XPATH_SELECTOR \
or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
exception_class = InvalidSelectorException
elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
exception_class = ElementNotSelectableException
elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
exception_class = ElementNotInteractableException
elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
exception_class = InvalidCookieDomainException
elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
exception_class = UnableToSetCookieException
elif status in ErrorCode.TIMEOUT:
exception_class = TimeoutException
elif status in ErrorCode.SCRIPT_TIMEOUT:
exception_class = TimeoutException
elif status in ErrorCode.UNKNOWN_ERROR:
exception_class = WebDriverException
elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
exception_class = UnexpectedAlertPresentException
elif status in ErrorCode.NO_ALERT_OPEN:
exception_class = NoAlertPresentException
elif status in ErrorCode.IME_NOT_AVAILABLE:
exception_class = ImeNotAvailableException
elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
exception_class = ImeActivationFailedException
elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
exception_class = MoveTargetOutOfBoundsException
elif status in ErrorCode.JAVASCRIPT_ERROR:
exception_class = JavascriptException
elif status in ErrorCode.SESSION_NOT_CREATED:
exception_class = SessionNotCreatedException
elif status in ErrorCode.INVALID_ARGUMENT:
exception_class = InvalidArgumentException
elif status in ErrorCode.NO_SUCH_COOKIE:
exception_class = NoSuchCookieException
elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
exception_class = ScreenshotException
elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
exception_class = ElementClickInterceptedException
elif status in ErrorCode.INSECURE_CERTIFICATE:
exception_class = InsecureCertificateException
elif status in ErrorCode.INVALID_COORDINATES:
exception_class = InvalidCoordinatesException
elif status in ErrorCode.INVALID_SESSION_ID:
exception_class = InvalidSessionIdException
elif status in ErrorCode.UNKNOWN_METHOD:
exception_class = UnknownMethodException
else:
exception_class = WebDriverException
if value == '' or value is None:
value = response['value']
if isinstance(value, basestring):
if exception_class == ErrorInResponseException:
raise exception_class(response, value)
raise exception_class(value)
if message == "" and 'message' in value:
message = value['message']
screen = None
if 'screen' in value:
screen = value['screen']
stacktrace = None
if 'stackTrace' in value and value['stackTrace']:
stacktrace = []
try:
for frame in value['stackTrace']:
line = self._value_or_default(frame, 'lineNumber', '')
file = self._value_or_default(frame, 'fileName', '<anonymous>')
if line:
file = "%s:%s" % (file, line)
meth = self._value_or_default(frame, 'methodName', '<anonymous>')
if 'className' in frame:
meth = "%s.%s" % (frame['className'], meth)
msg = " at %s (%s)"
msg = msg % (meth, file)
stacktrace.append(msg)
except TypeError:
pass
if exception_class == ErrorInResponseException:
raise exception_class(response, message)
elif exception_class == UnexpectedAlertPresentException and 'alert' in value:
raise exception_class(message, screen, stacktrace, value['alert'].get('text'))
> raise exception_class(message, screen, stacktrace)
E ElementClickInterceptedException: Message: Element <button class="ivu-btn ivu-btn-primary ivu-btn-long ivu-btn-small" type="button"> is not clickable at point (1193.3332901000977,522) because another element <div class="ivu-modal-wrap vertical-center-modal circuit-loading-modal"> obscures it
../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py:237: ElementClickInterceptedException
Upvotes: 4
Views: 3410
Reputation: 6064
The reason it fails because ElementToBeClickable
is waiting for element to be enabled, it's not really checking whether the element is clickable, it is assuming element is clickable if element is enabled, it's true actually but it fails here because element is enabled even when another element is overlay the desired element.
So write this code for the overlay to disappear
WebDriverWait(bspdriver.webdriver,10).until(EC.invisibility_of_element_located((By.XPATH, "//div[@class='ivu-modal-wrap vertical-center-modal circuit-loading-modal']")));
And then you write your code
what = (By.XPATH, '//button/span[contains(text(), "Load")]')
element = WebDriverWait(bspdriver.webdriver, 60).\
until(EC.element_to_be_clickable(what))
element.click()
The above solution would work if the overlay is temporary, If it's permanant, then perform the Javascript click, because WebDriver internal check would stop you to do the click.
Upvotes: 5