2017-09-13 65 views
9

Piszę testy Selenium z Selenium DSL ScalaTest i mam problemy z przekroczeniem limitu czasu, których nie potrafię wyjaśnić. Aby sprawy były bardziej skomplikowane, wydają się zdarzać tylko przez pewien czas.Dziwny limit czasu z ScalaTest's Selenium DSL

Problem pojawia się za każdym razem, gdy uzyskuję dostęp do elementu po wczytaniu strony lub renderowaniu JavaScript. Wygląda to tak:

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

My PatienceConfig jest skonfigurowany tak:

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

test nie powiedzie się z powodu następującego błędu:

- 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) 

to ma sens, że nie uda natychmiast, ponieważ click powoduje pewne renderowanie, a pole tekstowe może nie być dostępne od razu. Jednak nie powinno zająć 10 sekund, aby spróbować go znaleźć, prawda?

Uważam też, że bardzo interesujące jest to, że blok ostatecznie spróbował go tylko raz i że zajęło to prawie dokładnie 10 sekund. To pachnie jak timeout gdzieś, a to nie jest moja PatienceConfig, ponieważ ustawiono czas oczekiwania po 5 sekundach.

Z tego obejścia, to działa:

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

zrobiłem kilka kopanie w źródle ScalaTest, i zauważyłem, że wszystkie połączenia, które mają ten problem (nie tylko textField), ewentualnie zadzwonić webElement w pewnym momencie. Powodem, dla którego obejście tego problemu działa, jest to, że nie nazywa się webElement. webElement jest zdefiniowany następująco:

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 
       ) 
    } 
} 

mam kopiowane tego kodu do mojego projektu i bawił się z nim, i wygląda na to, budowy i/lub rzuca wyjątek, gdzie większość z 10 sekund są wydawane.

(EDIT Wyjaśnienie: Rzeczywiście widziałem, że kod rzeczywiście spędził 10 sekund wewnątrz bloku catch. Domyślne oczekiwanie jest ustawione na 0, a poza tym, jeśli usunę blok catch, wszystko po prostu działa zgodnie z oczekiwaniami.)

Moje pytanie brzmi, co mogę zrobić, aby uniknąć tego dziwnego zachowania? Nie chcę ciągle wstawiać zbędnych wywołań do find, ponieważ łatwo o tym zapomnieć, tym bardziej, że, jak powiedziałem, błąd występuje tylko przez pewien czas. (Nie byłem w stanie określić, kiedy zachowanie występuje, a kiedy nie.)

+0

Czy strona nadal ładuje się po przekroczeniu limitu czasu? Czy sprawdziłeś konsolę przeglądarki, aby sprawdzić, czy są jakieś błędy? Domyślam się, że strona ma zasób, którego nie można załadować, uniemożliwiając w ten sposób osiągnięcie stanu "pełnego" oczekiwanego przez sterownik. –

+0

Ale nawet jeśli tak jest, wywołanie 'driver.findElement' powinno po prostu zawieść (ponieważ domyślne oczekiwanie ma wartość 0), powinno przejść do bloku catch, a następnie' finally' sprawi, że spróbuje ponownie, prawda? – jqno

+0

domyślne ustawienie oczekiwania nie ma wpływu i nie jest związane z oczekiwaniem na ukończenie strony. Sterownik czeka na stronę [pełny stan] (https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState) na każdym poleceniu, chyba że opcja 'pageLoadingStrategy' jest ustawiona na' none' . –

Odpowiedz

1

Jest oczywiste, że textField(name("firstName")).value = "Steve" kończy się wywoływaniem WebElement, jak się dowiedziałeś. Ponieważ problem dotyczy tylko elementów sieciowych (co z kolei oznacza, że ​​zaangażowany jest webdriver), myślę, że można bezpiecznie założyć, że problem jest związany z niejawnym oczekiwaniem na sterownik sieciowy.

implicitlyWait(Span(0, Seconds)) 

Powyższe powinno idealnie rozwiązać problem. Co więcej, domyślne czekanie na 0 to zła praktyka. Każda strona internetowa może mieć pewne problemy z ładowaniem. Obciążenie strony jest obsługiwane przez Selenium poza warunkami oczekiwania. Ale powolne ładowanie elementów (może być spowodowane wywołaniami ajax) może spowodować awarię. Zwykle utrzymuję 10 sekund, ponieważ mój standard domyślnie czeka. W przypadku scenariuszy, które wymagają dłuższego oczekiwania, można zastosować wyraźne oczekiwania.

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

realizacji przepływu:

name("firstName") kończy się o wartość, 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 jest podawany sposobem, który wywołuje textFieldQuery.webElement poniżej.

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

Zwiększenie limitu czasu 'implicitlyWait' pomaga! Dzięki! Niestety nie udało mi się dotrzeć do tej odpowiedzi, zanim wygrała nagroda. – jqno

0

Nie znam szczegółów ScalaTest, ale takie dziwne przekroczenia czasu zwykle pojawiają się, gdy mieszasz niejawne i wyraźne oczekiwania razem .

driver.findElement używa ukrytych oczekiwań wewnętrznie. A w zależności od określonego czasu oczekiwania na konkretny czeka, możesz spotkać się z podsumowaniem obu razem.

Najlepiej, jeśli domyślne oczekiwania powinny mieć wartość 0, aby uniknąć takich problemów.

+0

Dzięki za sugestię, ale już skonfigurowałem domyślne oczekiwanie na 0. – jqno

+0

Użyj wyraźnego oczekiwania, które będzie czekać na kliknięcie elementu. –