![](/img/trans.png)
[英]StaleElementReferenceException selenium webdriver python
[英]StaleElementReferenceException occurs when clicking on the buttons of a changed table (Python > Selenium Webdriver)
当我尝试测试包含表的网页时,我不断收到StaleElementReferenceException。 该表包含点(以及一些其他信息)以及两个单独的阻止点的状态,每个阻止点的状态都为“是”和“否”的切换状态按钮。
在此特定代码中,过程为:
我在代码中添加了注释,以帮助遵循我的流程:
# << 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)
当某个点的所有“阻塞”状态都已删除时,它实际上从表中消失了,这是导致我异常的原因。 代码并非总是在同一行上失败,但是当它失败时,它总是在我试图单击“是”或“否”按钮的行上,这很可能是由于在一个点之后表发生了变化已成功从表中删除。
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”相一致。
到目前为止,我尝试在可能导致表更改的位置中同时使用time.sleep()和driver.implicitly_wait(),但问题仍然存在。 我该如何解决这个问题?
使用inplicitly_wait() ,如果时间设置得足够长,将解决StaleElementReferenceException问题。 但是,隐式等待也导致测试用例需要很长时间才能运行。 我使用在这里 , 这里和这里找到的想法解决了这个问题。
发生此问题的原因是,对表进行更改时,被引用的元素不再附加到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")
waitForNonStaleElement()用于确认元素不再陈旧。 waitForNonStaleElementClick()允许我单击可能是过时的元素。 waitForNonStaleElementText()允许我从可能过时的元素中检索文本。
然后,我使用以下方法重写了搜索代码:
# << 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")
希望这对某人遇到我遇到的相同问题会有所帮助。
如果您的问题是您单击了一个不存在的元素,并且想要验证是否存在该元素,则可以执行下一个操作:
您也可以尝试使用try-catch,但是它更复杂。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.