当前位置: 首页 > 面试题库 >

当我使用WebDriverWait而不是Thread.sleep时,我得到了StaleElementReferenceException

江向阳
2023-03-14
问题内容

我试图用groovy为Swagger页面编写Selenium对象构建器。为了便于讨论,我的问题代码可以简化为以下几种:

class SwaggerBuilder {

    WebDriver driver
    def resources

    SwaggerBuilder(WebDriver driver) {

        this.driver = driver

        Thread.sleep(2000)

        resources = driver.findElements(By.className("resource")).collectEntries {
            def resourceName = it.findElement(By.tagName("a")).getText().replaceFirst("[/]", "")
            [(resourceName): it]
        }
    }

    Object invokeMethod(String name, Object args) {

        if(resources[(name)] == null)
            throw new NoSuchElementException("Resource $name cannot be found.")

        resources[(name)].findElement(By.linkText("List Operations")).click()
    }
}

调用它非常简单(来自JUnit3):

void test1() {

    driver = new FirefoxDriver()
    driver.get("http://petstore.swagger.wordnik.com/")

    def petstore = new SwaggerBuilder(driver)    // problem does not get past this line!
    try {
        petstore.not_there()
        fail("Did not catch exception.")
    } catch(NoSuchElementException ex) {
        assertTrue(ex.message.startsWith("Resource not_there cannot be found."))
    } catch(Exception ex) {
        fail("Caught wrong exception: ${ex.class}.")
    }
}

Thread.sleep(2000)构造函数是一个可怕的眼睛痛!我试图用以下等待替换它:

def wait = new WebDriverWait(driver, 20)
wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("resource")))

要么:

    def wait = new FluentWait<By>(By.className("resource")).
            withTimeout(20, TimeUnit.SECONDS).
            pollingEvery(100, TimeUnit.MILLISECONDS).
            ignoring(StaleElementReferenceException)
    wait.until(new Function<By, Boolean>() {
                def count = 0
                @Override
                Boolean apply(By by) {
                    def oldCount = count
                    count = driver.findElements(by).size()
                    return count == oldCount
                }
            })

两者都产生了相同的结果:以开头的行中的闭包中的“
org.openqa.selenium.StaleElementReferenceException:元素不再连接到DOM” def resourceName = ...

Thread.sleep(2000)是我现在可以进行此工作的唯一方法。我希望将其替换为对浏览器更友好/更可靠的等待,因此即使对于加载速度低于2秒的页面也可以使用。还有其他想法吗?


问题答案:

加载页面时,我在控制台中看到了"Loaded SwaggerUI"三遍。那就是你的问题:SwaggerUI被加载了3次。

如何解决这个问题

所以我这样做:

  1. 我在打印出来的行上放置了一个断点"Loaded SwaggerUI"

  2. 我重装了。

  3. 当我达到断点时,我拍摄了具有该类的元素的快照resource

    var snap1 = Array.prototype.slice.call(
                document.getElementsByClassName("resource"))
    

(您必须将返回的值复制到一个Array(带有slice),因为它getElementsByClassName返回一个 实时 集合。)

  1. 我点击了调试器的继续按钮。

  2. 当我再次达到断点时,我拍摄了第二张快照(名为snap2)。

现在可以进行一些测试了。如果DOM没有更改,则元素应相同:

> snap1[0] === snap2[0]
false

看起来不太好。让我们看看DOM树中仍然有什么:

> document.contains(snap1[0])
false
> document.contains(snap2[0])
true

第一个快照中的元素不再在树中,而第二个快照中的元素在树中。

为什么硒错误?

2秒的等待时间足以让Selenium在DOM稳定之后开始查找元素。但是,当您告诉Selenium等待直到页面中有可见的class元素时resource,它就会等待直到
第一次 加载SwaggerUI 。在处理第一次找到的元素时,SwaggerUI 会加载另一个时间
,然后发现的旧元素不再在DOM树中。因此它提出了一个问题,StaleElementReferenceException因为它在DOM树中曾经发现的元素不再存在。它已替换为位于相同位置且结构相同的元素,但Selenium希望
完全相同的元素 而不是相同的副本。



 类似资料:
  • 我看过很多关于如何使用硒的示例脚本 switch_to.window 这是一个关于我所学的示例脚本,根本不起作用: 我得到了错误消息: InvalidArgumentException:预期“handle”为字符串,但得到了[object Undefined]未定义 很明显,我也厌倦了同样结果的普通网页。 有人有同样的问题吗?

  • 我正在为Kafka和SparkStreaming编写一些代码,当我将它们放在Yarn-Cluster上时,它报告了。 但它在我的电脑上运行良好(独立模式) 那它有什么问题呢? //这是代码 这里例外----------------------------------- 19/07/26 18:21:56警告Scheduler.TaskSetManager:在stage 0.0中丢失任务0.0(TI

  • 问题内容: 我写的http标签里面: 我有以下sas bean 在代码中,我从注册表中获取信息: 现在正在工作。 但是不赞成上课的问题 我这样替换了sas bean 但现在 总是返回空列表。 如何解决? PS完整配置: web.xml: 安全上下文: applicationContext.xml: dataContext.xml restTemplateContext.xml securityCo

  • 我与Wildfly和OpenJPA合作。我有一个乐观锁例外的情况。 我得到的错误消息是: 00:08:29373警告[com.arjuna.ats.arjuna](默认任务-39)arjuna01225:TwoPhaseCoordinator。beforeCompletion-SynchronizationImple失败 :org.apache.openjpa.persistence.乐观锁定异常

  • 我正在努力解决这个问题1438。绝对差值小于或等于极限的最长连续子阵列。我明白了逻辑,但有一个非常奇怪的问题,我不得不拉扯头发两个多小时。 代码如下:- 您可以看到,当我将一个整数放入每个队列时,代码运行良好,但当我将一个int放入三个队列时,我得到一个TLE。因此,在下面的代码中,如果temp是,则代码通过,但当temp是时,它会给出一个TLE。有人能解释一下发生了什么吗?

  • 我试图在数据库中的CLOB类型列中插入一个很长的字符串,它基本上是一个base64编码的图像字符串,但我得到了异常java.sql.sqlsyntaxerroreXception。做这件事的正确方法是什么? 我尝试了setClob()中的Clob对象和setClob()中的reader对象,但给出了相同的异常“java.sql.sqlsyntaxerrorexception”,并且我将OJDBC1