Django:Selenium-浏览器上的陈旧元素参考

Django: Selenium- stale element reference on browse

我正在使用 Chrome webdriver,因为 Firefox webdriver 在我的 Windows PC 上似乎有问题。

我的 Django 功能测试在我去度假之前工作得很好,但现在它们会抛出各种错误。

有时,当我尝试在页面上查找元素时,我得到:

selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document

其他时候,尝试验证 url 失败,因为 Selenium 似乎正在读取上一页的 URL。失败点似乎从运行变成了运行,换句话说,测试的某些部分在执行之间可以在成功和不成功之间交替。但是,问题似乎总是在使用 .click().

后出现

在查看浏览器时,Selenium 似乎已成功导航到该页面,所以我想它只是太快地寻找项目——在它们存在于浏览器之前。

implicitly.wait() 添加到我的 setUpClass 似乎没有帮助,但我可能用错了。

我尝试了 Harry Percival's site 中的有前途的想法(如下),但 Selenium 只是在等待页面时超时。

from contextlib import contextmanager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import \
    staleness_of
class MySeleniumTest(SomeFunctionalTestClass):
    # assumes self.browser is a selenium webdriver

    @contextmanager
    def wait_for_page_load(self, timeout=30):
        old_page = self.browser.find_element_by_tag_name('html')
        yield
        WebDriverWait(self.browser, timeout).until(
            staleness_of(old_page)
        )

    def test_stuff(self):
        # example use
        with self.wait_for_page_load(timeout=10):
            self.browser.find_element_by_link_text('a link')
            # nice!

有没有其他人处理过这个问题?我应该遵循什么正确的方法来解决这个问题?

编辑: 发布的解决方案非常有效并且真正清理了我的代码,因为我可以简单地将 .click() 添加到被调用函数,就像描述的那样。

以下是帮助我进行自定义的文档:

Documentation for the syntax for By for modification purposes.

Documentation for Selenium's Expected Conditions

注意:我使用术语 "browser" 代替驱动程序,我认为这是最初让我失望的原因。

wait_for_page_load一定要是发电机吗?我认为它会 return 无需等待!这就是为什么你的测试不稳定。有时元素会在您调用时加载 find_element_by_link_text 有时不会。

我已经成功地使用了这种方法:

from selenium.webdriver.support import expected_conditions as EC

def wait_for_element(self, elm, by = 'id', timeout=10) :
    wait = WebDriverWait(self.driver, timeout)
    if by == 'id' :
        element = wait.until(EC.element_to_be_clickable((By.ID,elm)))
        return self.driver.find_element_by_id(elm)
    elif by == 'link':
        wait.until(EC.element_to_be_clickable( (By.LINK_TEXT,elm)))
        return self.driver.find_element_by_link_text(elm)
    # by tag, by css etc etc goes here.

我使用 dom 元素的显着 ID 调用此方法,该元素应在与页面交互之前显示。 returned 元素可以直接交互。