Selenium Chrome Driver不尊重隐含的等待?

Ani*_*udh 1 java selenium-webdriver

好的!所以我在Windows 8上使用硒铬驱动程序(32位).

我已将隐式等待设置如下:

DesiredCapabilities des=DesiredCapabilities.chrome();
ChromeOptions options = new ChromeOptions();
options.addArguments("window-size=1366,768");
des.setCapability(ChromeOptions.CAPABILITY, options);
dvr= new ChromeDriver(des);
    driver = new EventFiringWebDriver(dvr);
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)

但在我的测试的某些时候,我得到一个staleElementException ...如下所示:

我并不太担心staleElementException,困扰我的是异常中的以下行:命令持续时间或超时:14毫秒

当超时已经隐含地设置为30秒时,为什么我得到14毫秒的超时....任何建议或解决方法将是appreaciate谢谢!

public static WebElement grabElementByPureXPath(String xpath)
{
    WebElement element = null;
    int attempts=1;
    try
    {
        while(attempts<7)
        {
            try
            {
                element=driver.findElement(By.xpath(xpath));
            }
            catch(StaleElementReferenceException e){}
                attempts++;
        }
    }
    catch(Throwable t)
    {
        try
        {
            element=driver.findElement(By.cssSelector(xpath));
        }
        catch(Throwable T)
        {
            takeScreenShot(xpath);
            Assert.assertTrue(t.getMessage(),false);
        }
    }

    return element;
}
Run Code Online (Sandbox Code Playgroud)

<-----------------------以下例外情况----------------------- ---------------------->

org.openqa.selenium.StaleElementReferenceException: stale element reference: element   is not attached to the page document
  (Session info: chrome=29.0.1547.76)
  (Driver info: chromedriver=2.1,platform=Windows NT 6.2 x86_64) (WARNING: The server did not provide any stacktrace information)
**Command duration or timeout: 14 milliseconds**
For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html
Build info: version: '2.35.0', revision: 'c916b9d', time: '2013-08-12 15:42:01'
System info: os.name: 'Windows 8', os.arch: 'amd64', os.version: '6.2', java.version: '1.7.0_25'
Session ID: aee4999cb9dc120f7e17629cc1621d7d
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{platform=WIN8, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={chromedriverVersion=2.1}, rotatable=false, locationContextEnabled=true, version=29.0.1547.76, cssSelectorsEnabled=true, databaseEnabled=true, handlesAlerts=true, browserConnectionEnabled=false, webStorageEnabled=true, nativeEvents=true, applicationCacheEnabled=false, takesScreenshot=true}]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:191)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:145)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:554)
    at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:268)
    at org.openqa.selenium.remote.RemoteWebElement.click(RemoteWebElement.java:79)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElement$1.invoke(EventFiringWebDriver.java:327)
    at com.sun.proxy.$Proxy12.click(Unknown Source)
    at org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElement.click(EventFiringWebDriver.java:340)
    at testCases.TC5663.test5663(TC5663.java:87)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.rules.Verifier$1.evaluate(Verifier.java:35)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runners.Suite.runChild(Suite.java:127)
    at org.junit.runners.Suite.runChild(Suite.java:26)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Run Code Online (Sandbox Code Playgroud)

/ **********---------------------********************** /


Pet*_*ček 6

编辑 - 您在此答案下面的评论和我对它的回答更接近您最初的要求:

根据记录的行为,StaleElementException似乎是隐含等待证明.在我看来,这似乎是Selenium的一个缺点.

它实际上与隐式等待无关.当元素被搜索时,它被发现了!然后改变了一些东西,元素被卸载并且可能再次加载,但你无法确定它在哪里.考虑一下:

driver.findElements(By.className("hello"));
Run Code Online (Sandbox Code Playgroud)

这找到12个元素,你从中获取第三个元素并尝试对它采取行动 - 但是oops,它现在已经过时了!硒应该做什么?

最合理的事情可能是重新找到所有元素并再次从中获取第三个元素.但页面明显改变了(因为元素是陈旧的),事实上,我们的元素现在不是第三,而是第四.而Selenium不可能知道这一点.怎么克服这个?


原始答案:

这是按预期工作的,它是记录在案的行为.

grabElementByPureXPath()找到并返回正确的元素.过了一会儿,当你click()在Selenium投掷时尝试找到这个元素时StaleElementReferenceException.

这通常发生在这样的情况:

  1. 您单击异步加载新页面或至少更改它的内容.
  2. 您可以立即(在页面加载完成之前)通过grabElementByPureXPath()... 搜索元素,然后找到并存储它!
  3. 页面最终卸载,新的页面加载.
  4. 您尝试使用click()之前找到的元素,但现在它已过时,即使新页面也包含相同的元素.但是从Selenium的观点来看,这只是你原始元素的同一个双胞胎,而不是原始元素本身.

隐式等待与此无关 - 元素被发现但现在不再存在.Selenium可能尝试使用By传递的原始对象再次搜索元素,但它故意不会.

您可以在我的答案中尝试其中一个解决方案:如何解决,陈旧元素异常?如果元素不再附加到DOM?


你的方法的最终挑剔.我知道你没有要求,但我觉得有必要告诉你:

  1. 你每次都会找到6次元素.即使它是在第一次尝试时发现的.改变你的状况

    while(attempts<7)
    
    Run Code Online (Sandbox Code Playgroud)

    while ((element == null) && (attempts < 7))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 这个:

    try
    {
        element=driver.findElement(By.xpath(xpath));
    }
    catch(StaleElementReferenceException e) {}
    
    Run Code Online (Sandbox Code Playgroud)

    从不触发.该StaleElementReferenceException不会发生,从来没有发生在driver.findElement().它根本不可能.此方法永远不会抛出异常.它只会抛出NoSuchElementException.

  3. 至少尝试评论空代码块.看到这样的代码有点令人困惑:

    catch(StaleElementReferenceException e){}
        attempts++;
    
    Run Code Online (Sandbox Code Playgroud)

    如果我没有寻找这样的问题,我可能会认为attempts增量只发生在StaleElementReferenceException类似的东西上.上面代码的通常和更易读的形式是:

    catch (StaleElementReferenceException e)
    {
        // do nothing
    }
    attempts++;
    
    Run Code Online (Sandbox Code Playgroud)

    评论空代码块还可以消除有人删除代码的风险.如果这不是一个try-catch块,而是一个没有代码的无参数构造函数,我强烈建议你在那里发表评论来解释为什么必须在那里明确地陈述构造函数(有时,它必须).否则,有人迟早会以错误的方式删除它/修改它.

  4. 搜索元素时,请不要简单地重试6次.出于以下几个原因这是错误的:

    • 它为您的代码带来了一个神奇的数字.魔术数字不好.
    • 它显然是任意选择的,没有任何评论解释为什么它确实是6.
    • 即使该方法被记录为重试6次,说"它将重试6次"对用户没有任何说明.
    • 它在不同浏览器或不同负载下的计算机上的行为会有所不同.重新搜索6次可能需要10秒才能在快速计算机和Chrome/Firefox上搜索id,但在IE7上通过某些复杂的XPath表达式或在负载较重的计算机上或远程计算机上搜索时可能需要30秒.

    请考虑使用超时.它可以很容易地记录,在每台计算机/浏览器上表现相同,每个人都明白了什么500 ms意思.编写它的最简单方法是:

    WebElement element = null;
    long targetTime = System.currentTimeMillis() + TIMEOUT_TIME;
    try
    {
        while ((element == null) && (System.currentTimeMillis() < targetTime))
        {
            try
            {
                element = driver.findElement(By.xpath(xpath));
            }
            catch (NoSuchElementException e) { /* do nothing */ }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 不要抓住Throwable t.如果你真的需要而且你知道为什么,请在旁边留言.捕获a Throwable被认为是一种不好的做法.看到这个这个.有关更多信息,请参阅Oracle官方Expections教程.

  6. 您不应该By.cssSelector()在调用的方法中搜索元素grabElementByPureXPath().方法应该只做它的名字(和文档)建议.删除/更改该代码,或将方法的名称更改为类似的grabElementByXPathOrCssSelector().

  7. 代替

    Assert.assertTrue(t.getMessage(), false);
    
    Run Code Online (Sandbox Code Playgroud)

    您可以使用

    Assert.fail(t.getMessage());
    
    Run Code Online (Sandbox Code Playgroud)

    它更短,更清楚地描述了你的意图.