Как я могу попросить Selenium-WebDriver подождать несколько секунд на Java?

101

Я работаю над Java Selenium-WebDriver. я добавил

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

и

WebElement textbox = driver.findElement(By.id("textbox"));

потому что моим приложениям требуется несколько секунд для загрузки пользовательского интерфейса. Поэтому я установил неявное ожидание в 2 секунды. но мне не удалось найти текстовое поле элемента

Затем я добавляю Thread.sleep(2000);

Теперь работает нормально. Какой способ лучше?

Принц
источник

Ответы:

123

Итак, есть два типа ожидания: явное и неявное. Идея явного ожидания

WebDriverWait.until(condition-that-finds-the-element);

Концепция неявного ожидания

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Вы можете узнать подробности здесь .

В таких ситуациях я бы предпочел использовать явное ожидание ( fluentWaitв частности):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWaitфункция возвращает найденный вами веб-элемент. Из документации fluentWait: реализация интерфейса ожидания, для которой время ожидания и интервал опроса могут быть настроены на лету. Каждый экземпляр FluentWait определяет максимальное время ожидания условия, а также частоту проверки условия. Кроме того, пользователь может настроить ожидание, чтобы игнорировать определенные типы исключений во время ожидания, такие как NoSuchElementExceptions, при поиске элемента на странице. Подробности вы можете получить здесь

Использование fluentWaitв вашем случае будет следующим:

WebElement textbox = fluentWait(By.id("textbox"));

Этот подход IMHO лучше, поскольку вы точно не знаете, сколько времени ждать, а в интервале опроса вы можете установить произвольное значение времени, через которое будет проверяться наличие элемента. С уважением.

Евгений Польщиков
источник
3
Это import com.google.common.base.Function;не такimport java.util.function.Function;
haventchecked
haventchecked, на самом деле использует intelij IDEA для разработки, помогает с автоматическим импортом (при работе в проекте на основе maven)
eugene.polschikov
1
Я просто призывал к этому других, которым могло быть интересно, что Functionбыло использовано. Сначала для меня это было неочевидно. Спасибо за ответ.
haventchered
1
Или вы могли бы просто использовать лямбда - выражение: driver -> driver.findElement(locator). При его использовании вам вообще не понадобится оператор импорта.
Thibstars 05
2
Теперь это: .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))вместо: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro
16

Эта ветка немного старше, но я подумал, что опубликую то, что я сейчас делаю (работа в процессе).

Хотя я все еще сталкиваюсь с ситуациями, когда система находится под большой нагрузкой, и когда я нажимаю кнопку отправки (например, login.jsp), все три условия (см. Ниже) возвращаются, trueно следующая страница (например, home.jsp) не работает. т еще не начал загружаться.

Это общий метод ожидания, который принимает список ожидаемых условий.

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

Я определил различные ожидаемые условия многократного использования (три ниже). В этом примере три ожидаемых условия включают document.readyState = 'complete', отсутствие "wait_dialog" и отсутствие "счетчиков" (элементы, указывающие, что запрашиваются асинхронные данные).

Только первый из них может применяться ко всем веб-страницам.

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

В зависимости от страницы я могу использовать один или все из них:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

Также есть предопределенные ExpectedConditions в следующем классе: org.openqa.selenium.support.ui.ExpectedConditions

Джефф Винсент
источник
1
Отличный ответ! Я никогда не видел, чтобы кто-то передавал элемент ExpectedCondition через конструктор метода. Какая отличная идея. +1
djangofan
Джефф Винсент, не могли бы вы сказать мне, сработает ли эта страница, чтобы подождать 5 минут, если да, то предложите, какой параметр места нужно отправить?
khanam
Это отличный ответ. У меня есть похожая функция, но я должен вызывать ее в каждой функции, чтобы мой сценарий ждал загрузки страницы (счетчик). Можно ли незаметно подключить эту функцию waitForSpinner к ImplicitWait, чтобы мне не приходилось вызывать ее каждый раз в моей функции? Подобно определению функции, подключите ее к драйверу один раз - и вперед.
Бхуванеш Мани
13

Если вы используете webdriverJs (node.js),

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

Приведенный выше код заставляет браузер ждать 5 секунд после нажатия кнопки.

Ануп
источник
18
Зачем вам публиковать это, если вопрос конкретно о Java, а не об узлах / JavaScript? Это так же не по теме, как отвечать на рубине, как это сделать.
Thor84no
1
рекомендация использовать сон определенно не лучшее решение
Кирилл С.
@ Thor84no В основном потому, что некоторые из нас, ищущих веб-решение, находят этот ответ
Китанга Ндай,
10

Использование Thread.sleep(2000);- это безусловное ожидание. Если ваш тест загружается быстрее, вам все равно придется подождать. Так что в принципе использование implicitlyWait- лучшее решение.

Однако я не понимаю, почему implicitlyWaitв вашем случае не работает. Вы измеряли, findElementдействительно ли требуется две секунды, прежде чем выбросить исключение. Если да, можете ли вы использовать условное ожидание WebDriver, как описано в этом ответе?

Валентин
источник
3

Мне нравится использовать индивидуальные условия. Вот код на Python:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

Когда вам нужно подождать, вы можете сделать это явно, проверив наличие определенного элемента (такой элемент может отличаться от страницы к странице). find_elements_by_idвозвращает список - пустой или нет, вам остается только проверить.

симно
источник
2

кажется, что щелчок блокирует? - вот еще один способ подождать, если вы используете WebDriverJS:

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

Приведенный выше код ожидает после нажатия кнопки загрузки следующей страницы, а затем захватывает источник следующей страницы.

Дион
источник
1
Что заставляет код ждать загрузки следующей страницы? Просто первый вызов в обратном вызове - это getPageSource?
Изохронный
1

Неявно wait и Thread.sleep Оба используются только для синхронизации .. но разница в том, что мы можем использовать неявно ждать для всей программы, но Thread.sleep будет работать только для этого единственного кода. Здесь мое предложение использовать неявно ждать один раз в программе когда каждый раз, когда ваша веб-страница будет обновляться, значит использовать Thread.sleep в то время .. это будет намного лучше :)

Вот мой код:

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}
Бекхэм Винот
источник
0

Иногда кажется, что неявное ожидание отменяется и время ожидания сокращается. [@ eugene.polschikov] имел хорошую документацию о том, почему. При тестировании и кодировании с помощью Selenium 2 я обнаружил, что неявное ожидание - это хорошо, но иногда приходится ждать явно.

Лучше избегать прямого вызова спящего потока, но иногда нет хорошего способа обойти это. Однако есть и другие варианты ожидания, предоставляемые Selenium, которые помогают. Особенно полезными оказались waitForPageToLoad и waitForFrameToLoad .

BadgerAndK
источник
0

Неявное ожидание: во время неявного ожидания, если веб-драйвер не может найти его немедленно из-за его доступности, веб-драйвер будет ждать указанное время и не будет пытаться найти элемент снова в течение указанного периода времени. По истечении указанного времени он попытается выполнить поиск элемента еще раз перед генерацией исключения. Значение по умолчанию - ноль. После того, как мы установим время, веб-драйвер ждет периода экземпляра объекта WebDriver.

Явное ожидание: может быть случай, когда для загрузки определенного элемента требуется больше минуты. В этом случае вам определенно не нравится устанавливать огромное время для неявного ожидания, поскольку если вы это сделаете, ваш браузер будет ждать одинаковое время для каждого элемента. Чтобы избежать этой ситуации, вы можете просто выделить время только для необходимого элемента. Следуя этому, ваш браузер неявно ждет время ожидания будет коротким для каждого элемента и большим для конкретного элемента.

Абхишек Сингх
источник
0

Иногда неявное ожидание терпит неудачу, говоря, что элемент существует, но на самом деле его нет.

Решение состоит в том, чтобы избежать использования driver.findElement и заменить его специальным методом, который неявно использует явное ожидание. Например:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

Есть дополнительные причины избегать неявного ожидания, кроме спорадических, случайных сбоев (см. Эту ссылку ).

Вы можете использовать этот "элементный" метод так же, как driver.findElement. Например:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

Если вы действительно хотите просто подождать несколько секунд для устранения неполадок или другого редкого случая, вы можете создать метод паузы, аналогичный тому, что предлагает selenium IDE:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
JohnP2
источник
0

Ответ : подождите несколько секунд, прежде чем видимость элемента с помощью Selenium WebDriver будет выполняться следующими способами.

implicitlyWait () : экземпляр WebDriver ожидает полной загрузки страницы. Вы можете использовать от 30 до 60 секунд, чтобы дождаться полной загрузки страницы.

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

ExplicitlyWait WebDriverWait () : экземпляр WebDriver ожидает полной загрузки страницы.

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

Заметка . Используйте ExplicitlyWait WebDriverWait () для обработки любого конкретного WebElement.

Sandeep Shewale
источник
0

Использовать действия -

Пользовательский API для эмуляции сложных пользовательских жестов.

См. Действия # метод паузы .

Дмитрий Санковский
источник
-1

Я предпочитаю, чтобы следующий код подождал 2 секунды.

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}
Гангадхар
источник
-1
Thread.sleep(1000);

хуже: статическое ожидание замедлит выполнение тестового сценария.

driver.manage().timeouts.implicitlyWait(10,TimeUnit.SECONDS);

это динамическое ожидание

  • он действителен до существования веб-драйвера или имеет область действия до времени жизни драйвера
  • мы также можем неявно ждать.

Наконец, я предлагаю

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

с некоторыми предопределенными условиями:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • Это также динамическое ожидание
  • в этом ожидание будет только в секундах
  • мы должны использовать явное ожидание определенного веб-элемента, который мы хотим использовать.
Shobhit
источник
-4
Thread.Sleep(5000);

Это помогло мне, но об исключении InterruptedException нужно позаботиться. Так что лучше окружите это попыткой поймать:

try {
    Thread.Sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

ИЛИ

Добавить объявление бросков:

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

Я бы предпочел второй, так как затем можно использовать sleep()столько раз, сколько захочет, и избежать повторения tryи catchблокировки каждый раз, где бы sleep()он ни использовался.

Прасад Хаджаре
источник