【问题标题】:Python-Selenium finds clickable element that cannot be clickedPython-Selenium 找到无法点击的可点击元素
【发布时间】:2018-08-14 12:49:54
【问题描述】:

我正在使用python-selenium 运行自动化测试。在运行这些测试的复杂非公共环境中,我发现了一些我将其标记为 selenium 中的错误的东西。

基本上我尝试做的是在 DOM 中找到一些元素,当它变为可点击时,然后点击它。代码如下:

....
what = (By.XPATH, '//button/span[contains(text(), "Load")]')
element = WebDriverWait(bspdriver.webdriver, 60).\
                until(EC.element_to_be_clickable(what))
element.click()
....

但是,click 方法几乎立即失败,并显示以下错误消息:

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

虽然我正在等待元素可点击!我认为EC.element_to_be_clickable 就是这个意思。但事实并非如此。这是硒中的错误吗?

解决方法是以下代码:

    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)

这对我来说看起来不太好。有没有办法改进代码?硒中有错误吗?如果是这样,我可以举报...

使用过的包:

  • 硒 3.8.0 和 3.11.0
  • geckodriver 0.19.1
  • python 2.7.12
  • py.test 3.6.1

完整的错误信息:

....
>       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

【问题讨论】:

    标签: python selenium


    【解决方案1】:

    它失败的原因是因为ElementToBeClickable正在等待元素被启用,它并没有真正检查元素是否可点击,如果元素被启用,它假设元素是可点击的,实际上是这样,但它在这里失败了,因为元素是即使在另一个元素覆盖所需元素时也启用。

    所以写这段代码让覆盖消失

    WebDriverWait(bspdriver.webdriver,10).until(EC.invisibility_of_element_located((By.XPATH, "//div[@class='ivu-modal-wrap vertical-center-modal circuit-loading-modal']")));
    

    然后你写你的代码

    what = (By.XPATH, '//button/span[contains(text(), "Load")]')
    element = WebDriverWait(bspdriver.webdriver, 60).\
                    until(EC.element_to_be_clickable(what))
    element.click()
    

    如果覆盖是临时的,上述解决方案将起作用,如果它是永久性的,则执行 Javascript 点击,因为 WebDriver 内部检查会阻止您进行点击。

    【讨论】:

    • 非常感谢这似乎奏效了!但也许我毕竟会提交一份错误报告,因为“点击”对我来说意味着“点击”......
    • @Alex 是的,没错!点击就是点击!
    • @Alex 我已经写了一个很好的答案,为什么 ElementToBeClickable 方法不等待元素可点击而是启用,所以我给出了一个更大的论据,为什么它不等待元素可点击,但很多人对我的答案投了反对票,所以我删除了它。
    • 如果我不能点击一个元素,它就不能点击。简单的逻辑。 Selenium 做错了!
    • @Alex 是的,确切地说,我与 JeffC 发生了更大的争论,他继续与我争论它仍然可以点击,然后我放弃了!请阅读这里的论点stackoverflow.com/questions/51654804/…
    猜你喜欢
    • 1970-01-01
    • 2021-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 2019-05-23
    • 2019-08-10
    相关资源
    最近更新 更多