WebDriver: проверьте, существует ли элемент?

Как проверить, существует ли элемент с веб-драйвером?

Является ли использование try catch действительно единственным возможным способом?

boolean present;
try {
   driver.findElement(By.id("logoutLink"));
   present = true;
} catch (NoSuchElementException e) {
   present = false;
}

Ответ 1

Вы также можете сделать:

driver.findElements( By.id("...") ).size() != 0

Что сохраняет неприятный try/catch

Ответ 2

Я согласен с ответом Майка, но там неявное 3-секундное ожидание, если не найдены никакие элементы, которые могут быть включены/выключены, что полезно, если вы много выполняете это действие:

driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS);
boolean exists = driver.findElements( By.id("...") ).size() != 0
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

Включение этого метода полезности должно повысить производительность, если вы выполняете множество тестов

Ответ 3

Как говорится в комментарии, это на С#, а не на Java, но идея такая же. Я исследовал эту проблему широко, и в конечном итоге проблема заключается в том, что FindElement всегда возвращает исключение, когда элемент не существует. Существует не перегруженный вариант, который позволяет вам получить нуль или что-то еще. Вот почему я предпочитаю это решение над другими.

  • Возвращает список элементов, а затем проверяет, работает ли размер списка 0, но вы тем самым теряете функциональность. Вы не можете сделать .click() в коллекции ссылок, даже если размер коллекции равен 1.
  • Вы можете утверждать, что элемент существует, но часто это останавливает ваше тестирование. В некоторых случаях у меня есть дополнительная ссылка для клика в зависимости от того, как я попал на эту страницу, и я хочу щелкнуть ее, если она существует, или перейти в противном случае.
  • Это будет только медленным, если вы не установите тайм-аут driver.Manage(). Timeouts(). ImplicitlyWait (TimeSpan.FromSeconds(0));
  • На самом деле это очень просто и элегантно после создания метода. Используя FindElementSafe вместо FindElement, я не вижу "уродливый блок try/catch", и я могу использовать простой метод Существует. Это будет выглядеть примерно так:

    IWebElement myLink = driver.FindElementSafe(By.Id("myId"));
    if (myLink.Exists)
    {
       myLink.Click();
    }
    

Вот как вы расширяете IWebElement и IWebDriver

IWebDriver.FindElementSafe

    /// <summary>
    /// Same as FindElement only returns null when not found instead of an exception.
    /// </summary>
    /// <param name="driver">current browser instance</param>
    /// <param name="by">The search string for finding element</param>
    /// <returns>Returns element or null if not found</returns>
    public static IWebElement FindElementSafe(this IWebDriver driver, By by)
    {
        try
        {
            return driver.FindElement(by);
        }
        catch (NoSuchElementException)
        {
            return null;
        }
    }

IWebElement.Exists

    /// <summary>
    /// Requires finding element by FindElementSafe(By).
    /// Returns T/F depending on if element is defined or null.
    /// </summary>
    /// <param name="element">Current element</param>
    /// <returns>Returns T/F depending on if element is defined or null.</returns>
    public static bool Exists(this IWebElement element)
    {
        if (element == null)
        { return false; }
        return true;
    }

Вы можете использовать полиморфизм для изменения экземпляра класса IWebDriver класса FindElement, но это плохая идея с точки зрения обслуживания.

Ответ 4

вы можете сделать утверждение.

см. пример

driver.asserts().assertElementFound("Page was not loaded",
By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT);

вы можете использовать это, это является родным:

public static void waitForElementToAppear(Driver driver, By selector, long timeOutInSeconds, String timeOutMessage) {
    try {
      WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
      wait.until(ExpectedConditions.visibilityOfElementLocated(selector));
    } catch (TimeoutException e) {
      throw new IllegalStateException(timeOutMessage);
    }
  }

Ответ 5

Это работает для меня каждый раз:

    if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
        //THEN CLICK ON THE SUBMIT BUTTON
    }else{
        //DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
    }

Ответ 6

Я расширил реализацию Selenium WebDriver, в моем случае HtmlUnitDriver выставляет метод

public boolean isElementPresent(By by){}

вот так:

  • проверьте, загружена ли страница в течение периода ожидания.
  • Как только страница загружена, я опускаю неявное время ожидания WebDriver до нескольких миллисекунд, в моем случае 100 мельниц, вероятно, также должны работать с 0 мельницами.
  • вызов findElements (By), WebDriver, даже если не найдет элемент, будет ждать только количество времени сверху.
  • верните неявное время ожидания для загрузки следующей страницы.

Вот мой код:

import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

public class CustomHtmlUnitDriver extends HtmlUnitDriver {

    public static final long DEFAULT_TIMEOUT_SECONDS = 30;
    private long timeout = DEFAULT_TIMEOUT_SECONDS;

    public long getTimeout() {
        return timeout;
    }
    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }

    public boolean isElementPresent(By by) {
        boolean isPresent = true;
        waitForLoad();
        //search for elements and check if list is empty
        if (this.findElements(by).isEmpty()) {
            isPresent = false;
        }
        //rise back implicitly wait time
        this.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);
        return isPresent;
    }

    public void waitForLoad() {
        ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver wd) {
                //this will tel if page is loaded
                return "complete".equals(((JavascriptExecutor) wd).executeScript("return document.readyState"));
            }
        };
        WebDriverWait wait = new WebDriverWait(this, timeout);
        //wait for page complete
        wait.until(pageLoadCondition);
        //lower implicitly wait time
        this.manage().timeouts().implicitlyWait(100, TimeUnit.MILLISECONDS);
    }   
}

Использование:

CustomHtmlUnitDriver wd = new CustomHtmlUnitDriver();
wd.get("http://example.org");
if (wd.isElementPresent(By.id("Accept"))) {
    wd.findElement(By.id("Accept")).click();
}
else {
    System.out.println("Accept button not found on page");
}

Ответ 7

Напишите следующий метод с использованием Java:

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

Вызовите вышеуказанный метод во время утверждения.

Ответ 8

String link = driver.findElement(By.linkText(linkText)).getAttribute("href")

Это даст вам ссылку, на которую указывает элемент.

Ответ 9

С версией 2.21.0 selenium-java.jar вы можете это сделать;

driver.findElement(By.id("...")).isDisplayed()

Ответ 10

Как я понимаю, это стандартный способ использования веб-драйвера.