Sprawdź, czy element jest obecny przy użyciu Selenium WebDriver?

163

Czy istnieje sposób sprawdzenia, czy element jest obecny? Każda metoda findElement zakończyłaby się wyjątkiem, ale nie tego chcę, ponieważ może się zdarzyć, że element nie jest obecny i to jest w porządku, to nie oznacza niepowodzenia testu, więc wyjątek nie może być rozwiązaniem.

Znalazłem ten post: Selenium c # Webdriver: Czekaj, aż element jest obecny Ale to jest dla C # i nie jestem w tym zbyt dobry. Czy ktoś może przetłumaczyć kod na Javę? Przepraszam chłopaki, wypróbowałem to w Eclipse, ale nie rozumiem tego od razu w kodzie Java.

To jest kod:

public static class WebDriverExtensions{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds){

        if (timeoutInSeconds > 0){
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }

        return driver.FindElement(by);
    }
}
próbnik
źródło
Mam kilka metod, które bardzo skutecznie sprawdzają obecność obiektu, ale to zależy od tego, co chcesz z nim zrobić. na przykład czy chcesz szukać elementu, dopóki nie istnieje, czy chcesz go szukać, aż już nie istnieje, czy chcesz po prostu spróbować go znaleźć?
CBRRacer
1
Java jest bardzo podobna do C # Myślę, że jednym z głównych problemów, z którymi się tu spotykasz, jest java to WebElement zamiast IWebElement
CBRRacer
Czy wiesz o niejawnej metodzie oczekiwania? Ustawiając to na początku testu, nigdy nie musisz sprawdzać istnienia elementu, ponieważ używa on niejawnej wartości oczekiwania do sondowania, jednak jeśli przekroczy tę wartość, zgłosi wyjątek
Bob Evans
Oto mój post o WebDriverWait w Javie: WebDriverWait
Jeśli którykolwiek przypadek jest prawidłowy, może to być problematyczne dla wydajności testu, ponieważ czas oczekiwania związany z oczekiwaniem na element, którego nie spodziewasz się istnieć, naprawdę się sumuje. Użyłem kilku hacków, aby obejść czas oczekiwania, ale jeszcze nie znalazłem naprawdę czystego rozwiązania tego problemu.
mrfreester

Odpowiedzi:

277

Użyj findElementszamiast findElement.

findElements zwróci pustą listę, jeśli zamiast wyjątku nie zostaną znalezione żadne pasujące elementy.

Aby sprawdzić, czy element jest obecny, możesz spróbować tego

Boolean isPresent = driver.findElements(By.yourLocator).size() > 0

To zwróci wartość true, jeśli zostanie znaleziony co najmniej jeden element i false, jeśli nie istnieje.

Oficjalna dokumentacja zaleca tę metodę:

findElement nie powinien być używany do wyszukiwania nieobecnych elementów, zamiast tego użyj findElements (By) i zapewnij odpowiedź o zerowej długości.

el roso
źródło
32
Wydłuży to dużo czasu na przeprowadzenie testów. Nie możesz używać tej techniki wszędzie.
Droogans,
8
@Droogans - nie będę dodawał czasu do twoich testów. Przyczyną tego jest to, że domyślne niejawne oczekiwanie nadal wynosi 0. Jeśli zwiększyłeś domyślne domyślne oczekiwanie, zgadzam się, że tak będzie, ale nie wydaje się, aby tak było w tym przypadku.
djangofan
1
Dobry telefon djangofan! Z powodzeniem zastosowałem tę strategię, zmieniając niejawny czas oczekiwania sterownika na zero, a następnie zmieniając go z powrotem na poprzednią wartość.
szmergiel
3
Dało to wyjątek NoSuchElementFound, co jest wstydem, ponieważ miałem nadzieję użyć tego, aby uniknąć przechwytywania tego wyjątku w danej instancji.
1
Znacznie łatwiejszym sposobem jest użycie: if (driver.getPageSource (). Zawiera ("Tekst na stronie")) {} Jeśli strona zawiera ten tekst, warunek będzie prawdziwy, albo będzie fałszywy i możesz kodować odpowiednio.
pradyot
56

A co z metodą prywatną, która po prostu wyszukuje element i określa, czy jest obecny w ten sposób:

private boolean existsElement(String id) {
    try {
        driver.findElement(By.id(id));
    } catch (NoSuchElementException e) {
        return false;
    }
    return true;
}

Byłoby to dość łatwe i spełnia swoje zadanie.

Edycja: możesz nawet pójść dalej i wziąć By elementLocatorparametr jako, eliminując problemy, jeśli chcesz znaleźć element za pomocą czegoś innego niż id.

Dennis
źródło
3
Tak, to jest droga. Nie rozumiem, dlaczego ludzie ignorują w ten sposób i liczą pasujące elementy, sprawdzając, czy wynik to 0.
Ralph Lavelle
45
Cóż, muszę powiedzieć, że używanie wyjątków do regulowania przepływu programu nie jest najlepszym rozwiązaniem.
Dennis
2
Co? To była twoja sugestia! Jest to dobry sposób, jeśli test nie przewiduje znalezienia elementu. Jak pokazujesz, po prostu zwróć null i assert.isnull lub isnotnull, co jest znaczącym sposobem sprawdzenia, czy coś istnieje.
Ralph Lavelle
2
W przypadku, gdy źle zinterpretowałem pytanie „czy istnieje sposób, jak sprawdzić, czy element jest obecny?” źle, z przyjemnością dowiem się, dlaczego twoja opinia jest inna, czy jest to uzasadniona odpowiedź.
Dennis
może chcieć skrócić czas oczekiwania. W tej chwili, jeśli element nie istnieje, musisz poczekać „30 sekund”, zanim funkcja zwróci wartość false
Jason Smiley
14

Zauważyłem, że to działa dla Java:

WebDriverWait waiter = new WebDriverWait(driver, 5000);
waiter.until( ExpectedConditions.presenceOfElementLocated(by) );
driver.FindElement(by);
Tango Ben
źródło
18
presenceOfElementLocatedzgłosi wyjątek, jeśli element nie zostanie znaleziony przy żadnej konkretnej próbie. Aby tego uniknąć, dodaj wait.ignoring(NoSuchElementException.class);instrukcję między pierwszą a drugą linią.
Steve Chambers
8
public static WebElement FindElement(WebDriver driver, By by, int timeoutInSeconds)
{
    WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
    wait.until( ExpectedConditions.presenceOfElementLocated(by) ); //throws a timeout exception if element not present after waiting <timeoutInSeconds> seconds
    return driver.findElement(by);
}
RedDeckWins
źródło
5

Miałem ten sam problem. Dla mnie, w zależności od poziomu uprawnień użytkownika, niektóre linki, przyciski i inne elementy nie będą się wyświetlać na stronie. Część mojego pakietu testowała, czy brakuje elementów, których POWINIEN brakować. Spędziłem godziny, próbując to rozgryźć. W końcu znalazłem idealne rozwiązanie.

Powoduje to, że przeglądarka ma szukać wszystkich określonych elementów na podstawie. Jeśli tak 0, oznacza to, że nie znaleziono żadnych elementów opartych na specyfikacji. Następnie mam kod, aby wykonać instrukcję if, aby poinformować mnie, że nie została znaleziona.

To jest w C#, więc tłumaczenia musiałyby być zrobione Java. Ale nie powinno być zbyt trudne.

public void verifyPermission(string link)
{
    IList<IWebElement> adminPermissions = driver.FindElements(By.CssSelector(link));
    if (adminPermissions.Count == 0)
    {
        Console.WriteLine("User's permission properly hidden");
    }
}

Istnieje również inna ścieżka, którą możesz wybrać w zależności od tego, czego potrzebujesz do testu.

Poniższy fragment służy do sprawdzania, czy na stronie nie ma określonego elementu. W zależności od istnienia elementu test wykonuję if else.

Jeśli element istnieje i jest wyświetlany na stronie, dałem console.writemi znać i przechodzę dalej. Jeśli dany element istnieje, nie mogę wykonać testu, którego potrzebowałem, co jest głównym powodem, dla którego muszę to skonfigurować.

Jeśli element nie istnieje i nie jest wyświetlany na stronie. Mam else w if else wykonuje test.

IList<IWebElement> deviceNotFound = driver.FindElements(By.CssSelector("CSS LINK GOES HERE"));
//if the element specified above results in more than 0 elements and is displayed on page execute the following, otherwise execute whats in the else statement
if (deviceNotFound.Count > 0 && deviceNotFound[0].Displayed){
    //script to execute if element is found
} else {
    //Test script goes here.
}

Wiem, że jestem trochę spóźniony z odpowiedzią na OP. Mam nadzieję, że to komuś pomoże!

Tasza
źródło
5

Spróbuj tego: wywołaj tę metodę i przekaż 3 argumenty:

  1. Zmienna WebDriver. // zakładając zmienną_ driver jako kierowcę.
  2. Element, który zamierzasz sprawdzić. Powinien zapewnić według metody. // np. By.id ("id")
  3. Limit czasu w sekundach.

Przykład: waitForElementPresent (driver, By.id ("id"), 10);

public static WebElement waitForElementPresent(WebDriver driver, final By by, int timeOutInSeconds) {

        WebElement element; 

        try{
            driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait() 

            WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds); 
            element = wait.until(ExpectedConditions.presenceOfElementLocated(by));

            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //reset implicitlyWait
            return element; //return the element
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return null; 
    }
Prabu Ananthakrishnan
źródło
3

Możesz przyspieszyć działanie kodu, skracając limit czasu selenu przed instrukcją try catch.

Używam następującego kodu, aby sprawdzić, czy element jest obecny.

protected boolean isElementPresent(By selector) {
    selenium.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
    logger.debug("Is element present"+selector);
    boolean returnVal = true;
    try{
        selenium.findElement(selector);
    } catch (NoSuchElementException e){
        returnVal = false;
    } finally {
        selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
    }
    return returnVal;
}
Ezoteryczny nonsens
źródło
Tego właśnie używam w moim kodzie. Zostawiam domyślny limit czasu Selenium, a następnie używam tego.
Nicholas DiPiazza
2
Od napisania tej odpowiedzi dowiedziałem się, że użycie ExpectedConditions jest uważane za lepszą formę, ale użycie instrukcji try catch jest nadal przydatne podczas próby określenia, czy element nie jest obecny.
EsotericNonsense
Utknąłem na starej wersji selenu, ponieważ muszę przetestować IE8. ale spróbuję tego, kiedy będę mógł uaktualnić
Nicholas DiPiazza
Za każdym razem, gdy twoja metoda ustawi niejawny limit czasu oczekiwania, ale logicznie powinniśmy ustawić niejawne oczekiwanie tylko raz po zainicjowaniu obiektu sterownika i ustawieniu limitu czasu na sesję sterownika.
Shekhar Swami
3

Napisz następującą funkcję / metody w Javie:

protected boolean isElementPresent(By by){
        try{
            driver.findElement(by);
            return true;
        }
        catch(NoSuchElementException e){
            return false;
        }
    }

Wywołaj metodę z odpowiednim parametrem podczas asercji.

Ripon Al Wasim
źródło
2

jeśli używasz rspec-Webdriver w Rubim, możesz użyć tego skryptu, zakładając, że element naprawdę nie powinien być obecny i jest to pozytywny test.

Najpierw napisz tę metodę najpierw z pliku klasy RB

class Test
 def element_present?
    begin
        browser.find_element(:name, "this_element_id".displayed?
        rescue Selenium::WebDriver::Error::NoSuchElementError
            puts "this element should not be present"
        end
 end

Następnie w pliku specyfikacji wywołaj tę metodę.

  before(:all) do    
    @Test= Test.new(@browser)
  end

 @Test.element_present?.should == nil

Jeśli twój element NIE jest obecny, twoja specyfikacja przejdzie, ale jeśli element jest obecny, wyrzuci błąd, test się nie powiódł.

szara
źródło
2

To działa dla mnie:

 if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
    //THEN CLICK ON THE SUBMIT BUTTON
}else{
    //DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
}
Amstel Bytes
źródło
ten sam problem istnieje tutaj: co się stanie, jeśli element „// * [@ id = 'submit']” nie istnieje? wtedy zostanie wyrzucony wyjątek, więc warunek warunkowy if nigdy nie jest oceniany
MrBCut
1
public boolean isElementDisplayed() {
        return !driver.findElements(By.xpath("...")).isEmpty();
    }
Bogdan Shulga
źródło
1

Osobiście zawsze wybieram kombinację powyższych odpowiedzi i tworzę statyczną metodę Utility wielokrotnego użytku, która wykorzystuje size() > 0sugestię:

public Class Utility {
   ...
   public static boolean isElementExist(WebDriver driver, By by) {
      return driver.findElements(by).size() > 0;
   ...
}

To jest schludne, nadające się do ponownego użycia, w utrzymaniu ... wszystkie te dobre rzeczy ;-)

Charlie Seligman
źródło
0

Aby znaleźć konkretny element jest obecny lub nie, musimy użyć metody findElements () zamiast findElement ().

int i=driver.findElements(By.xpath(".......")).size();
if(i=0)
System.out.println("Element is not present");
else
System.out.println("Element is present");

to działa dla mnie .. zasugeruj mi, jeśli się mylę ..

Subbarao Gaddam
źródło
0

To powinno wystarczyć:

try {
    driver.findElement(By.id(id));
} catch (NoSuchElementException e) {
    //do what you need here if you were expecting
    //the element wouldn't exist
}
Scott Helme
źródło
0

Podaję mój fragment kodu. Zatem poniższa metoda sprawdza, czy na stronie istnieje przycisk „ Utwórz nową aplikację ” losowego elementu WWW, czy nie. Zauważ, że użyłem okresu oczekiwania jako 0 sekund.

public boolean isCreateNewApplicationButtonVisible(){
    WebDriverWait zeroWait = new WebDriverWait(driver, 0);
    ExpectedCondition<WebElement> c = ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@value='Create New Application']"));
    try {
        zeroWait.until(c);
        logger.debug("Create New Application button is visible");
        return true;
    } catch (TimeoutException e) {
        logger.debug("Create New Application button is not visible");
        return false;
    }
}
Rambo7
źródło
0

Użyłbym czegoś takiego (ze Scalą [kod w starej „dobrej” Javie 8 może być podobny do tego]):

object SeleniumFacade {

  def getElement(bySelector: By, maybeParent: Option[WebElement] = None, withIndex: Int = 0)(implicit driver: RemoteWebDriver): Option[WebElement] = {
    val elements = maybeParent match {
      case Some(parent) => parent.findElements(bySelector).asScala
      case None => driver.findElements(bySelector).asScala
    }
    if (elements.nonEmpty) {
      Try { Some(elements(withIndex)) } getOrElse None
    } else None
  }
  ...
}

a więc wtedy,

val maybeHeaderLink = SeleniumFacade getElement(By.xpath(".//a"), Some(someParentElement))
ses
źródło
0

Najprostszy sposób, jaki znalazłem w Javie to:

List<WebElement> linkSearch=  driver.findElements(By.id("linkTag"));
int checkLink=linkSearch.size();
if(checkLink!=0){  //do something you want}
back2back
źródło
0

Możesz spróbować niejawnego oczekiwania:

WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));

Lub możesz spróbować jawnie czekać jeden:

IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
    {
        return d.FindElement(By.Id("someDynamicElement"));
    });

Jawnie sprawdzi, czy element jest obecny przed jakąś akcją. Niejawne oczekiwanie można wywołać w każdym miejscu kodu. Na przykład po niektórych akcjach AJAX.

Więcej na stronie SeleniumHQ

streser
źródło