2017-09-13 21 views
9

我正在写与ScalaTest的硒DSL Selenium测试,我运行到超时,我无法解释。为了使事情更加复杂,他们似乎只是在某些时候发生。奇怪暂停时以ScalaTest的硒DSL

的问题,每当我一个页面加载或一些JavaScript渲染后访问一个元素出现。它看起来像这样:

click on "editEmployee" 
eventually { 
    textField(name("firstName")).value = "Steve" 
} 

我PatienceConfig配置是这样的:

override implicit val patienceConfig: PatienceConfig = 
    PatienceConfig(timeout = Span(5, Seconds), interval = Span(50, Millis)) 

测试失败,出现以下错误:

- should not display the old data after an employee was edited *** FAILED *** 
    The code passed to eventually never returned normally. Attempted 1 times over 10.023253653000001 seconds. 
    Last failure message: WebElement 'firstName' not found.. (EditOwnerTest.scala:24) 

这是有道理的,也不会成功立即,因为click导致一些呈现,并且文本字段可能无法立即可用。但是,它不应该花10秒来尝试找到它,对吧?

而且,我觉得很有意思的是,最终块试了一次,而且它用了近正是10秒。这听起来像是在某个地方发生的超时,并且它不是我的PatienceConfig,因为它在5秒后设置为超时。

有了这个解决方案,它的工作:

click on "editEmployee" 
eventually { 
    find(name("firstName")).value // from ScalaTest's `OptionValues` 
} 
textField(name("firstName")).value = "Steve" 

我的确在ScalaTest源的一些挖,我已经注意到,有这个问题的所有电话(这不只是textField),最终调用webElement在某一点。解决方法的原因是因为它不会调用webElementwebElement的定义是这样的:

def webElement(implicit driver: WebDriver, pos: source.Position = implicitly[source.Position]): WebElement = { 
    try { 
    driver.findElement(by) 
    } 
    catch { 
    case e: org.openqa.selenium.NoSuchElementException => 
     // the following is avoid the suite instance to be bound/dragged into the messageFun, which can cause serialization problem. 
     val queryStringValue = queryString 
     throw new TestFailedException(
       (_: StackDepthException) => Some("WebElement '" + queryStringValue + "' not found."), 
       Some(e), 
       pos 
       ) 
    } 
} 

我复制的代码到我的项目,与它玩耍了,它看起来像建造和/或抛出异常是大多数的10秒中度过。说明:我已经看到代码实际上在catch块中花费了10秒,隐含的wait设置为0,此外,如果我删除了catch块,那么一切都按预期工作。 )

所以我的问题是,我能做些什么来避免这种奇怪的行为?我不想一直插入多余的电话到find,因为它很容易被人遗忘,特别是因为,正如我所说的,错误只发生在一些时间。 (我一直无法确定什么时候出现的问题,当它没有。)

+0

发生超时时页面是否仍在加载?您是否检查过浏览器控制台以查看是否有任何错误?我的猜测是页面有一个资源无法加载,从而阻止页面达到驱动程序期望的“完成”状态。 –

+0

但即使是这样,driver.findElement调用应该会失败(因为隐式等待设置为0),它应该去catch块,然后“最终”会让它再试一次,对吧? – jqno

+0

隐式等待设置没有影响,并且与等待页面完成无关。除非能力'pageLoadingStrategy'被置'none'为页面[完整状态(https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState)上的每个命令驾驶员等待。 –

回答

1

很明显,textField(name("firstName")).value = "Steve"最终会调用WebElement,因为你已经发现了。 由于操作中的问题发生在任何涉及web元素的地方(这又意味着涉及webdriver),所以我认为可以安全地认为该问题与Web驱动程序中的隐式等待有关。

implicitlyWait(Span(0, Seconds)) 

上面应该理想地解决这个问题。此外,使隐含的等待为0是不好的做法。任何网页可能有一些加载问题。页面加载由Selenium在等待条件之外处理。但是缓慢的元素负载(可能是由于ajax调用)可能导致失败。我通常保持10秒钟,因为我的标准隐式等待。对于需要更多等待的场景,可以使用明确的等待。

def implicitlyWait(timeout: Span)(implicit driver: WebDriver): Unit = { 
driver.manage.timeouts.implicitlyWait(timeout.totalNanos, TimeUnit.NANOSECONDS) 
} 

执行流程为:

name("firstName")结束有值作为Query {Val by = By.className("firstName") }

def name(elementName: String): NameQuery = new NameQuery(elementName) 

case class NameQuery(queryString: String) extends Query { val by = By.name(queryString) } 

Query被馈送到textField方法,其调用Query.webElement如下。

def textField(query: Query)(implicit driver: WebDriver, pos: source.Position): TextField = new TextField(query.webElement)(pos) 

sealed trait Query extends Product with Serializable { 

    val by: By 

    val queryString: String 

    def webElement(implicit driver: WebDriver, pos: source.Position = implicitly[source.Position]): WebElement = { 
     try { 
     driver.findElement(by) 
     } 
     catch { 
     case e: org.openqa.selenium.NoSuchElementException => 
      // the following is avoid the suite instance to be bound/dragged into the messageFun, which can cause serialization problem. 
      val queryStringValue = queryString 
      throw new TestFailedException(
        (_: StackDepthException) => Some("WebElement '" + queryStringValue + "' not found."), 
        Some(e), 
        pos 
        ) 
     } 
    } 
    } 
+0

增加'隐式等待'超时确实有帮助!谢谢!可悲的是,在赏金到期之前,我无法得到这个答案。 – jqno

0

我不知道ScalaTest的细节,但这种奇特的超时,当你隐性和显性等待混合在一起,通常会出现。

driver.findElement使用隐式等待内部。根据指定的显式等待超时,您可能会面临将两者一起求和的情况。

理想情况下,应将隐含等待设置为0以避免此类问题。

+0

感谢您的建议,但我已经有配置的隐等待为0 – jqno

+0

使用明确的等待,这将等待元素被点击。 –