单击已更改表的按钮时发生 StaleElementReferenceException (Python > Selenium Webdriver) [英] StaleElementReferenceException occurs when clicking on the buttons of a changed table (Python > Selenium Webdriver)

查看:18
本文介绍了单击已更改表的按钮时发生 StaleElementReferenceException (Python > Selenium Webdriver)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试测试包含表格的网页时,我不断收到 StaleElementReferenceException.该表包含点 [以及其他一些信息] 和两个单独的阻止点的状态,每个阻止点都有一个用于是"和否"的切换状态按钮.

I keep geting a StaleElementReferenceException when I'm trying to test a webpage that contains a table. The table has points [as well as some other info] and the status of two separate Blocking points, each of which has a toggle state button for 'Yes' and 'No'.

在这个特定的代码中,过程是:

In this particular code, the process is:

  1. 点击复选框仅显示阻塞点.
  2. 如果表中没有阻塞点,您就完成了.否则...
  3. 在第一行保存点的名称&检查第一个阻塞状态.如果设置为是",请将其更改为否".
  4. 检查该点是否仍然存在.如果是,请将第二个阻止状态更改为否"并确认该点已被删除.

我在代码中添加了注释以帮助遵循我的流程:

I added comments in the code to help follow my process:

    # << Setup >>
    driver.get(url("/PointsTable/"))
    assertExpectedConditionTrue(driver, "By.XPATH", "//td")

    # < Confirm that the points blocking checkbox is enabled >
    if not driver.find_element_by_id("BlockedPoints").is_selected():
        assertExpectedConditionTrue(driver, "By.ID", "BlockedPoints")
        driver.find_element_by_id("BlockedPoints").click()
        assertCheckBoxEnabled(driver, "BlockedPoints")

    # < First check if any points have a blocking state >
    try:
        assertExpectedConditionTrue(driver, "By.XPATH", "//td[contains(text(), 'No data available in table')]", None, 3)
    except (NoSuchElementException):
        # < Until all the points are out of blocking state, begin changing blocking statuses
        #   to all the points >
        while True:
            # < Check if all the points are set to have no blocking statuses set to Yes >
            try:
                assertExpectedConditionFalse(driver, "By.XPATH", "//td[contains(text(), 'No data available in table')]", None, 2)
            except (NoSuchElementException, TimeoutException):
                break

            # < Save the name of the point
            # Check the first blocking status.  If it is blocking, set the block to No >
            assertExpectedConditionTrue(driver, "By.XPATH", "//td")
            myPointVal = driver.find_element_by_xpath("//td").text

            try:
                assertExpectedConditionTrue(driver, "By.XPATH", "//tbody/tr[1]/td[5]/div/button[@class='btn active btn-success btn-small point-button']", None, 2)
            except (NoSuchElementException):
                assertExpectedConditionTrue(driver, "By.XPATH", "//tbody/tr[1]/td[5]/div/button[@class='btn btn-small point-button']")
                driver.find_element_by_xpath("//tbody/tr[1]/td[5]/div/button[@class='btn btn-small point-button']").click()

            # < Save the name of the point again.  Compare it to the original saved point
            #    If the name is the same, then the second blocking status needs to be set to No
            #    If the name is different, that means the point in question is no longer blocked >
            assertExpectedConditionTrue(driver, "By.XPATH", "//td")
            if myPointVal == driver.find_element_by_xpath("//td").text:
                assertExpectedConditionTrue(driver, "By.XPATH", "//tbody/tr[1]/td[6]/div/button[@class='btn btn-small point-button']")
                driver.find_element_by_xpath("//tbody/tr[1]/td[6]/div/button[@class='btn btn-small point-button']").click()
                assertExpectedConditionFalse(driver, "By.XPATH", "//td", myPointVal)

当一个点的所有阻塞状态都被移除时,它就会从表格中消失,这就是我出现异常的原因.代码并不总是在同一行上失败,但是当它失败时,它总是在我尝试单击是"或否"按钮的那一行上,这很可能是由于在某个点之后表发生了变化已成功从表中删除.

When a point has had all its Blocking states removed, it literally disappears from the table, which is the cause of my exception. The code doesn't always fail on the same line, but when it fails, it's ALWAYS on a line where I attempt to click on the 'Yes' or 'No' button, more than likely due to the table changing after a point has been successfully removed from the table.

i.e. driver.find_element_by_xpath("//tbody/tr[1]/td[6]/div/button[@class='btn btn-small point-button']").click()

有时会超过这部分代码 &在我尝试单击按钮之后的不同部分失败.. (1) 刷新页面,或 (2) 导航到第二页,其中 XPATH 地址相同,但对象在 XPATH 地址已更改.由于此处列出的原因,我确实理解我遇到此问题的原因.我的问题似乎与元素不再附加到 DOM"一致.

It sometimes makes it past this portion of the code & fails in a different portion where I'm attempting to click on a button either after I've.. (1) refreshed the page, or (2) have navigated to page two, where the XPATH addresses are the same, but the objects in the XPATH address have changed. I do understand the reason I'm having this issue for the reasons listed here. My issue seems to be consistent with, "The element is no longer attached to the DOM."

到目前为止,我已经尝试在可能导致表更改的位置同时使用 time.sleep() 和 driver.implicitly_wait(),但问题仍然存在.我该如何解决这个问题?

Up to this point, I've tried using both time.sleep() and driver.implicitly_wait() in locations that could cause change to the table, but the issue still remains. How can I resolve this issue?

推荐答案

使用 inplicitly_wait(),如果时间设置得足够高,将解决 StaleElementReferenceException 问题.但是,隐式等待也导致测试用例需要很长时间才能运行.我使用在 here此处这里.

Using an inplicitly_wait(), if the time is set high enough, will resolve StaleElementReferenceException issue. However, the implicit wait also caused the test case to take a very long time to run. I resolved this issue using ideas I found here, here, and here.

发生此问题的原因是,在对表格进行更改时,所引用的元素不再附加到 DOM.因此,我专门为处理可能过时的元素创建了定义.

The issue occurred because elements that were being referenced were no longer be attached to the DOM when changes were made to the table. Therefore, I created definitions specifically for dealing with elements that may be stale.

def waitForNonStaleElement(driver, type, element):
    strategy = {
            "id":           driver.find_element_by_id,
            "link_text":    driver.find_element_by_link_text,
            "name":         driver.find_element_by_name,
            "xpath":        driver.find_element_by_xpath
            }
    lhsType, rhsType = type.split(".", 1)
    find_element = strategy.get(rhsType.lower())

    try:
        find_element(element)
    except StaleElementReferenceException:
        waitForNonStaleElement(driver, type, element)
    except TypeError:
        raise TypeError("ERROR : CODE TO HANDLE \""+element+"\" TYPE NEEDS TO BE CREATED")


def waitForNonStaleElementClick(driver, type, element):
    strategy = {
            "id":           driver.find_element_by_id,
            "link_text":    driver.find_element_by_link_text,
            "name":         driver.find_element_by_name,
            "xpath":        driver.find_element_by_xpath
            }
    lhsType, rhsType = type.split(".", 1)
    find_element = strategy.get(rhsType.lower())

    try:
        waitForNonStaleElement(driver, type, element)
        find_element(element).click()
    except StaleElementReferenceException:
        waitForNonStaleElementClick(driver, type, element)
    except TypeError:
        raise TypeError("ERROR : CODE TO HANDLE \""+element+"\" TYPE NEEDS TO BE CREATED")


def waitForNonStaleElementText(driver, type, element):
    strategy = {
            "id":           driver.find_element_by_id,
            "link_text":    driver.find_element_by_link_text,
            "name":         driver.find_element_by_name,
            "xpath":        driver.find_element_by_xpath
            }
    lhsType, rhsType = type.split(".", 1)
    find_element = strategy.get(rhsType.lower())

    try:
        return find_element(element).text
    except StaleElementReferenceException:
        waitForNonStaleElementText(driver, type, element)
    except TypeError:
        raise TypeError("ERROR : CODE TO HANDLE \""+element+"\" TYPE NEEDS TO BE CREATED")

waitForNonStaleElement() 用于确认元素不再陈旧.waitForNonStaleElementClick() 允许我点击可能过时的元素.waitForNonStaleElementText() 允许我从可能过时的元素中检索文本.

waitForNonStaleElement() is used for confirming the an element is no longer stale. waitForNonStaleElementClick() allows me click on an element that could be stale. waitForNonStaleElementText() allows me to retrieve text from an element that may be stale.

然后我使用这些方法重写了搜索代码:

I then rewrote the search code using these methods:

# << Setup >>
driver.get(url("/PointsBlocking/"))
assertExpectedConditionTrue(driver, "By.XPATH", "//td")

if not driver.find_element_by_id("BlockedOnlyCheckbox").is_selected():
    assertExpectedConditionTrue(driver, "By.ID", "BlockedOnlyCheckbox")
    driver.find_element_by_id("BlockedOnlyCheckbox").click()
    assertCheckBoxEnabled(driver, "BlockedOnlyCheckbox")

waitForNonStaleElement(driver, "By.XPATH", "//td")

try:
    assertExpectedConditionTrue(driver, "By.XPATH", "//td", "No data available in table", 1)
except (TimeoutException):
    while True:
        try:
            assertExpectedConditionFalse(driver, "By.XPATH", "//td", "No data available in table", 1)
        except (TimeoutException):
            break

        assertExpectedConditionTrue(driver, "By.XPATH", "//td")
        pointName = waitForNonStaleElementText(driver, "By.XPATH", "//td")

        try:
            assertExpectedConditionTrue(driver, "By.XPATH", "//tbody/tr[1]/td[5]/div/button[@class='btn active btn-success btn-small point-button']", None, 1)
        except NoSuchElementException:
            assertExpectedConditionTrue(driver, "By.XPATH", "//tbody/tr[1]/td[5]/div/button[@class='btn btn-small point-button']")
            waitForNonStaleElementClick(driver, "By.XPATH", "//tbody/tr[1]/td[5]/div/button[@class='btn btn-small point-button']")

        tmp = waitForNonStaleElementText(driver, "By.XPATH", "//td")

        if pointName == tmp:
            assertExpectedConditionTrue(driver, "By.XPATH", "//tbody/tr[1]/td[6]/div/button[@class='btn btn-small point-button']")
            waitForNonStaleElementClick(driver, "By.XPATH", "//tbody/tr[1]/td[6]/div/button[@class='btn btn-small point-button']")
            waitForNonStaleElementClick(driver, "By.XPATH", "//td")

希望这会对遇到我遇到的相同问题的人有所帮助.

Hopefully, this will help someone if they run across the same issue I did.

这篇关于单击已更改表的按钮时发生 StaleElementReferenceException (Python &gt; Selenium Webdriver)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆