单击更改表的按钮时发生StaleElementReferenceException(Python>Selenium Webdriver)

2024-10-02 10:26:02 发布

您现在位置:Python中文网/ 问答频道 /正文

当我尝试测试包含表的网页时,我一直获取StaleElementReferenceException。表中有点[以及一些其他信息]和两个单独的阻塞点的状态,每个阻塞点都有一个切换状态按钮,分别表示“是”和“否”。在

在本规范中,过程是:

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

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

    # << 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)

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

^{pr2}$

它有时会使它越过代码的这一部分,而在另一个部分中失败,即在我尝试单击某个按钮之后,在另一个部分中失败。。(1) 刷新页面,或者(2)导航到第二页,其中XPATH地址相同,但XPATH地址中的对象已更改。我确实理解我出现这个问题的原因,原因如下here。我的问题似乎与“元素不再附加到DOM”一致

到目前为止,我都试过使用这两种方法时间。睡觉()和driver.implicitly_wait驱动程序()位于可能导致表更改的位置,但问题仍然存在。我如何解决这个问题?在


Tags: thetobyisdriverbuttonelementfind
2条回答

如果时间设置得足够高,则使用inpolicytly_wait()将解决StaleElementReferenceException问题。然而,隐式等待也导致测试用例需要很长时间才能运行。我用找到的herehere和{a3}的思想解决了这个问题。在

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

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")

waitForNonSaleElement()用于确认元素不再过时。waitForNonSaleElementClick()允许我单击可能过时的元素。waitForNonSaleElementText()允许我从可能过时的元素中检索文本。在

然后我使用以下方法重写搜索代码:

^{pr2}$

希望,如果有人遇到和我一样的问题,这会对他们有所帮助。在

如果您的问题是您单击了一个不存在的元素,并且希望验证元素是否存在,则可以执行下一步操作:

  1. 使用搜索元素列表的方法查找元素(同时返回list)
  2. 检查列表中是否有任何元素(count>;0)
  3. 如果count为0,则找不到元素,因此它不存在

也可以尝试使用try-catch,但它更复杂。在

相关问题 更多 >

    热门问题