Mam nadzieję, że to tylko ja, ale Selenium Webdriver wydaje się kompletnym koszmarem. Sterownik sieciowy Chrome jest obecnie bezużyteczny, a inne sterowniki są dość zawodne, a przynajmniej tak się wydaje. Walczę z wieloma problemami, ale oto jeden.
Losowo, moje testy zakończą się niepowodzeniem z rozszerzeniem
"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'"
Używam wersji webdriver 2.0b3. Widziałem, jak to się dzieje w przypadku sterowników FF i IE. Jedynym sposobem, w jaki mogę temu zapobiec, jest dodanie rzeczywistego wywołania Thread.sleep
przed wystąpieniem wyjątku. Jest to jednak kiepskie obejście, więc mam nadzieję, że ktoś wskaże błąd z mojej strony, który to wszystko poprawi.
java
selenium-webdriver
webdriver
automated-tests
Ray Nicholus
źródło
źródło
from selenium.common.exceptions import NoSuchElementException
Odpowiedzi:
Tak, jeśli masz problemy ze StaleElementReferenceExceptions, oznacza to, że twoje testy są źle napisane. To stan wyścigu. Rozważ następujący scenariusz:
Teraz w miejscu, w którym klikasz element, odwołanie do elementu nie jest już prawidłowe. Jest prawie niemożliwe, aby WebDriver mógł dobrze odgadnąć wszystkie przypadki, w których może się to zdarzyć - więc podnosi ręce i daje kontrolę Tobie, który jako autor testu / aplikacji powinien dokładnie wiedzieć, co może się wydarzyć, a co nie. To, co chcesz zrobić, to wyraźnie poczekać, aż DOM znajdzie się w stanie, w którym wiesz, że nic się nie zmieni. Na przykład użycie WebDriverWait, aby poczekać, aż zaistnieje określony element:
Metoda presentOfElementLocated () wyglądałaby mniej więcej tak:
Masz rację co do tego, że obecny sterownik Chrome jest dość niestabilny i z przyjemnością usłyszysz, że tułów Selenium ma przepisany sterownik Chrome, w którym większość implementacji została wykonana przez programistów Chromium w ramach ich drzewa.
PS. Alternatywnie, zamiast czekać jawnie, jak w powyższym przykładzie, możesz włączyć niejawne oczekiwanie - w ten sposób WebDriver będzie zawsze zapętlał się do określonego limitu czasu oczekiwania na pojawienie się elementu:
Jednak z mojego doświadczenia wynika, że jawne czekanie jest zawsze bardziej niezawodne.
źródło
com.google.common.base.Function<F, T>
dostarczone przez firmę Guava .Udało mi się zastosować taką metodę z pewnym sukcesem:
Tak, po prostu sonduje element, dopóki nie przestanie być uważany za nieaktualny (świeży?). Naprawdę nie dociera do źródła problemu, ale odkryłem, że WebDriver może być dość wybredny w rzucaniu tego wyjątku - czasami to rozumiem, a czasami nie. Albo może być tak, że DOM naprawdę się zmienia.
Więc nie do końca zgadzam się z powyższą odpowiedzią, że to koniecznie wskazuje na źle napisany test. Mam to na nowych stronach, z którymi w żaden sposób nie wchodziłem w interakcję. Myślę, że jest trochę niestabilności w sposobie reprezentowania DOM lub w tym, co WebDriver uważa za przestarzałe.
źródło
Ten błąd pojawia się czasami, gdy aktualizacje AJAX są w połowie. Kapibara wydaje się być całkiem sprytna, jeśli chodzi o czekanie na zmiany DOM (zobacz Dlaczego wait_until został usunięty z Kapibary ), ale domyślny czas oczekiwania wynoszący 2 sekundy był po prostu niewystarczający w moim przypadku. Zmienione w _spec_helper.rb_ z np
źródło
Miałem dzisiaj ten sam problem i stworzyłem klasę opakowania, która sprawdza przed każdą metodą, czy odwołanie do elementu jest nadal prawidłowe. Moje rozwiązanie do odzyskania elementu jest dość proste, więc pomyślałem, że po prostu go udostępnię.
Widzisz i „lokalizuję”, a raczej zapisuję element w globalnej zmiennej js i w razie potrzeby pobieram element. Jeśli strona zostanie ponownie załadowana, odniesienie nie będzie już działać. Ale tak długo, jak wprowadzane są tylko zmiany zagłady, pozostaje odniesienie. I to powinno wystarczyć w większości przypadków.
Unika również ponownego przeszukiwania elementu.
Jan
źródło
Miałem ten sam problem i mój był spowodowany starą wersją selenu. Nie mogę zaktualizować do nowszej wersji ze względu na środowisko programistyczne. Problem jest spowodowany przez HTMLUnitWebElement.switchFocusToThisIfNeeded (). Po przejściu do nowej strony może się zdarzyć, że element, który kliknąłeś na starej stronie to
oldActiveElement
(patrz poniżej). Selen próbuje uzyskać kontekst ze starego elementu i kończy się niepowodzeniem. Dlatego stworzyli próbny haczyk w przyszłych wydaniach.Kod z wersji sterownika selenium-htmlunit <2.23.0:
Kod z wersji selenium-htmlunit-driver> = 2.23.0:
Bez aktualizacji do wersji 2.23.0 lub nowszej możesz po prostu nadać fokus dowolnemu elementowi. Właśnie użyłem
element.click()
na przykład.źródło
Po prostu zdarzyło mi się, gdy próbowałem wysłać klucze do pola wyszukiwania - które ma automatyczną aktualizację w zależności od tego, co wpisujesz. Jak wspomniała Eero, może się to zdarzyć, jeśli twój element zaktualizuje Ajax podczas wpisywania tekstu wewnątrz elementu wejściowego . Rozwiązaniem jest wysyłanie po jednym znaku na raz i ponowne wyszukiwanie elementu wejściowego . (Np. Rubinem pokazanym poniżej)
źródło
Aby dodać do odpowiedzi @ jarib, stworzyłem kilka metod rozszerzających, które pomagają wyeliminować stan wyścigu.
Oto moja konfiguracja:
Mam klasę o nazwie „Driver.cs”. Zawiera statyczną klasę pełną metod rozszerzających dla sterownika i innych przydatnych funkcji statycznych.
Dla elementów, które zwykle muszę pobierać, tworzę metodę rozszerzenia, taką jak poniżej:
Pozwala to na pobranie tego elementu z dowolnej klasy testowej z kodem:
Teraz, jeśli to skutkuje
StaleElementReferenceException
, mam następującą metodę statyczną w mojej klasie sterownika:Pierwszym parametrem tej funkcji jest dowolna funkcja, która zwraca obiekt IWebElement. Drugi parametr to limit czasu w sekundach (kod limitu czasu został skopiowany z Selenium IDE dla FireFox). Kod może służyć do uniknięcia nieaktualnego wyjątku elementu w następujący sposób:
Powyższy kod będzie wywoływał,
driver.SpecificElementToGet().Displayed
dopókidriver.SpecificElementToGet()
nie zgłosi żadnych wyjątków i.Displayed
wylicza do,true
a 5 sekund nie minie. Po 5 sekundach test zakończy się niepowodzeniem.Z drugiej strony, aby poczekać, aż element nie będzie obecny, możesz użyć następującej funkcji w ten sam sposób:
źródło
Myślę, że znalazłem wygodne podejście do obsługi StaleElementReferenceException. Zwykle musisz napisać otoki dla każdej metody WebElement, aby ponowić działania, co jest frustrujące i marnuje dużo czasu.
Dodanie tego kodu
przed każdą akcją WebElement może zwiększyć stabilność testów, ale nadal możesz od czasu do czasu uzyskać StaleElementReferenceException.
Oto, co wymyśliłem (używając AspectJ):
Aby włączyć ten aspekt, utwórz plik
src\main\resources\META-INF\aop-ajc.xml
i napiszDodaj to do swojego
pom.xml
I to wszystko. Mam nadzieję, że to pomoże.
źródło
Możesz rozwiązać ten problem, używając jawnego czekania, aby nie musieć używać twardego czekania.
Jeśli pobierasz wszystkie elementy z jedną właściwością i iterujesz po niej używając dla każdej pętli, możesz użyć wait wewnątrz pętli w ten sposób,
lub dla pojedynczego elementu możesz użyć poniższego kodu,
źródło
W Javie 8 możesz użyć do tego bardzo prostej metody :
źródło
źródło