Ich hoffe, es ist nur ich, aber Selenium Webdriver scheint ein Albtraum zu sein. Der Chrome-Webdriver ist derzeit unbrauchbar, und die anderen Treiber sind anscheinend ziemlich unzuverlässig. Ich kämpfe mit vielen Problemen, aber hier ist eines.
Zufällig schlagen meine Tests mit a fehl
"org.openqa.selenium.StaleElementReferenceException: Element is no longer attached
to the DOM
System info: os.name: 'Windows 7', os.arch: 'amd64',
os.version: '6.1', java.version: '1.6.0_23'"
Ich verwende Webdriver-Versionen 2.0b3. Ich habe dies bei FF- und IE-Treibern gesehen. Die einzige Möglichkeit, dies zu verhindern, besteht darin, einen tatsächlichen Aufruf hinzuzufügen, Thread.sleep
bevor die Ausnahme auftritt. Das ist jedoch eine schlechte Problemumgehung, daher hoffe ich, dass jemand auf einen Fehler meinerseits hinweisen kann, der das alles besser macht.
java
selenium-webdriver
webdriver
automated-tests
Ray Nicholus
quelle
quelle
from selenium.common.exceptions import NoSuchElementException
Antworten:
Ja, wenn Sie Probleme mit StaleElementReferenceExceptions haben, liegt dies daran, dass Ihre Tests schlecht geschrieben sind. Es ist eine Rennbedingung. Stellen Sie sich das folgende Szenario vor:
An dem Punkt, an dem Sie auf das Element klicken, ist die Elementreferenz nicht mehr gültig. Für WebDriver ist es nahezu unmöglich, alle Fälle zu erraten, in denen dies passieren könnte. Daher wirft es die Hände hoch und gibt Ihnen die Kontrolle, wer als Test- / App-Autor genau wissen sollte, was passieren kann oder nicht. Sie möchten explizit warten, bis sich das DOM in einem Zustand befindet, in dem Sie wissen, dass sich nichts ändert. Verwenden Sie beispielsweise ein WebDriverWait, um auf das Vorhandensein eines bestimmten Elements zu warten:
Die PresenceOfElementLocated () -Methode würde ungefähr so aussehen:
Sie haben völlig Recht damit, dass der aktuelle Chrome-Treiber ziemlich instabil ist, und Sie werden erfreut sein zu hören, dass der Selenium-Trunk über einen neu geschriebenen Chrome-Treiber verfügt, bei dem der größte Teil der Implementierung von den Chromium-Entwicklern als Teil ihres Baums durchgeführt wurde.
PS. Anstatt explizit wie im obigen Beispiel zu warten, können Sie auch implizite Wartezeiten aktivieren. Auf diese Weise wird WebDriver immer bis zum angegebenen Zeitlimit wiederholt, bis das Element vorhanden ist:
Nach meiner Erfahrung ist explizites Warten jedoch immer zuverlässiger.
quelle
com.google.common.base.Function<F, T>
, bereitgestellt von Guava .Ich konnte eine Methode wie diese mit einigem Erfolg anwenden:
Ja, das Element wird nur so lange abgefragt, bis es nicht mehr als abgestanden (frisch?) Betrachtet wird. Kommt dem Problem nicht wirklich auf den Grund, aber ich habe festgestellt, dass der WebDriver beim Auslösen dieser Ausnahme ziemlich wählerisch sein kann - manchmal verstehe ich es und manchmal nicht. Oder es könnte sein, dass sich das DOM wirklich ändert.
Daher stimme ich der obigen Antwort nicht ganz zu, dass dies notwendigerweise auf einen schlecht geschriebenen Test hinweist. Ich habe es auf neuen Seiten, mit denen ich in keiner Weise interagiert habe. Ich denke, es gibt eine gewisse Unschärfe darin, wie das DOM dargestellt wird oder was WebDriver als veraltet ansieht.
quelle
Ich erhalte diesen Fehler manchmal, wenn AJAX-Updates auf halbem Weg sind. Capybara scheint ziemlich schlau zu sein, auf DOM-Änderungen zu warten (siehe Warum wait_until aus Capybara entfernt wurde ), aber die Standardwartezeit von 2 Sekunden war in meinem Fall einfach nicht genug. Geändert in _spec_helper.rb_ mit z
quelle
Ich hatte heute das gleiche Problem und habe eine Wrapper-Klasse erstellt, die vor jeder Methode prüft, ob die Elementreferenz noch gültig ist. Meine Lösung, um das Element abzurufen, ist ziemlich einfach, also dachte ich, ich würde es einfach teilen.
Sie sehen, dass ich das Element in einer globalen js-Variablen "finde" oder vielmehr speichere und es bei Bedarf abrufe. Wenn die Seite neu geladen wird, funktioniert diese Referenz nicht mehr. Solange jedoch nur Änderungen vorgenommen werden, um das Schicksal zu verhindern, bleibt die Referenz erhalten. Und das sollte in den meisten Fällen funktionieren.
Außerdem wird vermieden, dass das Element erneut durchsucht wird.
John
quelle
Ich hatte das gleiche Problem und mein Problem wurde durch eine alte Selenversion verursacht. Ich kann aufgrund der Entwicklungsumgebung nicht auf eine neuere Version aktualisieren. Das Problem wird durch HTMLUnitWebElement.switchFocusToThisIfNeeded () verursacht. Wenn Sie zu einer neuen Seite navigieren, kann es vorkommen, dass das Element, auf das Sie auf der alten Seite geklickt haben, das ist
oldActiveElement
(siehe unten). Selen versucht, den Kontext aus dem alten Element zu erhalten und schlägt fehl. Aus diesem Grund haben sie in zukünftigen Versionen einen Try-Catch erstellt.Code aus der Version <2.23.0 des Selenium-HTML-Einheitentreibers:
Code aus der Version des Selenium-HTML-Einheitentreibers> = 2.23.0:
Ohne ein Update auf 2.23.0 oder neuer können Sie einfach ein beliebiges Element im Seitenfokus angeben. Ich habe gerade
element.click()
zum Beispiel verwendet.quelle
Das ist mir gerade passiert, als ich versucht habe, Schlüssel in ein Eingabefeld für die Suche zu senden. Je nachdem, was Sie eingeben, wird automatisch aktualisiert. Wie von Eero erwähnt, kann dies passieren, wenn Ihr Element einige Ajax-Aktualisierungen vornimmt, während Sie Ihren Text in das Eingabeelement eingeben . Die Lösung besteht darin , jeweils ein Zeichen zu senden und erneut nach dem Eingabeelement zu suchen . (Bsp. In Rubin unten gezeigt)
quelle
Um die Antwort von @ jarib zu ergänzen, habe ich verschiedene Erweiterungsmethoden entwickelt, die dazu beitragen, die Rennbedingung zu beseitigen.
Hier ist mein Setup:
Ich habe eine Klasse namens "Driver.cs". Es enthält eine statische Klasse voller Erweiterungsmethoden für den Treiber und andere nützliche statische Funktionen.
Für Elemente, die ich normalerweise abrufen muss, erstelle ich eine Erweiterungsmethode wie die folgende:
Auf diese Weise können Sie dieses Element aus einer beliebigen Testklasse mit dem folgenden Code abrufen:
Wenn dies zu a führt
StaleElementReferenceException
, habe ich die folgende statische Methode in meiner Treiberklasse:Der erste Parameter dieser Funktion ist eine Funktion, die ein IWebElement-Objekt zurückgibt. Der zweite Parameter ist eine Zeitüberschreitung in Sekunden (der Code für die Zeitüberschreitung wurde aus der Selenium IDE für FireFox kopiert). Der Code kann verwendet werden, um die veraltete Elementausnahme auf folgende Weise zu vermeiden:
Der obige Code wird aufgerufen,
driver.SpecificElementToGet().Displayed
bisdriver.SpecificElementToGet()
keine Ausnahmen.Displayed
ausgelöst und ausgewertet werdentrue
und 5 Sekunden nicht vergangen sind. Nach 5 Sekunden schlägt der Test fehl.Auf der anderen Seite können Sie die folgende Funktion auf die gleiche Weise verwenden, um darauf zu warten, dass ein Element nicht vorhanden ist:
quelle
Ich denke, ich habe einen bequemen Ansatz gefunden, um mit StaleElementReferenceException umzugehen. Normalerweise müssen Sie für jede WebElement-Methode Wrapper schreiben, um Aktionen erneut zu versuchen. Dies ist frustrierend und verschwendet viel Zeit.
Diesen Code hinzufügen
Bevor jede WebElement-Aktion die Stabilität Ihrer Tests erhöhen kann, können Sie dennoch von Zeit zu Zeit eine StaleElementReferenceException erhalten.
Das habe ich mir also ausgedacht (mit AspectJ):
Um diesen Aspekt zu aktivieren, erstellen Sie eine Datei
src\main\resources\META-INF\aop-ajc.xml
und schreiben SieFügen Sie dies Ihrem hinzu
pom.xml
Und das ist alles. Ich hoffe es hilft.
quelle
Sie können dies durch explizites Warten lösen, sodass Sie nicht lange warten müssen.
Wenn Sie alle Elemente mit einer Eigenschaft abrufen und mit jeder Eigenschaft durchlaufen, können Sie wie folgt in der Schleife warten.
oder für ein einzelnes Element können Sie den folgenden Code verwenden:
quelle
In Java 8 können Sie dafür eine sehr einfache Methode verwenden :
quelle
quelle