Подтвердить что ты не робот

Selenium WebDriver: Свободное ожидание работает, как ожидалось, но неявное ожидание не

Я новичок в Selenium WebDriver и пытаюсь понять правильный способ "подождать" для присутствия элементов.

Я тестирую страницу с кучей вопросов с ответами на радиокнопках. Когда вы выбираете ответы, Javascript может включать/отключать некоторые из вопросов на странице.

Проблема заключается в том, что Selenium "слишком быстро нажимает" и не ждет завершения Javascript. Я попытался решить эту проблему двумя способами - явное ожидание решило проблему. В частности, это работает и решает мою проблему:

private static WebElement findElement(final WebDriver driver, final By locator, final int timeoutSeconds) {
    FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(timeoutSeconds, TimeUnit.SECONDS)
            .pollingEvery(500, TimeUnit.MILLISECONDS)
            .ignoring(NoSuchElementException.class);

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

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

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

Это не решает проблему, и я получаю исключение NoSuchElementException. Кроме того, я не замечаю паузу в 10 секунд - это просто ошибки сразу. Я проверил эту строку в коде, который попадает в отладчик. Что я делаю не так? Почему implicitlyWait не дожидаться появления элемента, но FluentWait делает?

Примечание. Как я уже говорил, у меня уже есть работа, я просто хочу знать, почему Implicit wait не решает мою проблему. Спасибо.

4b9b3361

Ответ 1

Помните, что существует разница между несколькими сценариями:

  • Элемент, не присутствующий вообще в DOM.
  • Элемент присутствует в DOM, но не отображается.
  • Элемент присутствует в DOM, но не включен. (т.е. интерактивно)

Я предполагаю, что если какая-то страница отображается с помощью javascript, элементы уже присутствуют в DOM браузера, но не отображаются. Неявное ожидание ожидает только того, что элемент появится в DOM, поэтому он немедленно возвращается, но когда вы пытаетесь взаимодействовать с элементом, вы получаете исключение NoSuchElementException. Вы можете проверить эту гипотезу, написав вспомогательный метод, который explicits ожидает, что элемент будет видимым или кликабельным.

Некоторые примеры (на Java):

public WebElement getWhenVisible(By locator, int timeout) {
    WebElement element = null;
    WebDriverWait wait = new WebDriverWait(driver, timeout);
    element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
    return element;
}

public void clickWhenReady(By locator, int timeout) {
    WebDriverWait wait = new WebDriverWait(driver, timeout);
    WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator));
    element.click();
}

Ответ 2

Основная идея заключается в следующем:

Явное ожидание

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;
};

Надеюсь, что это поможет)

Ответ 3

Слово предупреждения для общей ошибки:

После того, как вы установите неявное ожидание, вы не можете использовать явное или свободное время, пока не вернетесь в неявное ожидание. Это означает, что ExpectedConditions, которые содержат вызовы driver.findElement, не будут работать должным образом с неявным ожиданием! Вы часто сталкиваетесь с случаями, когда вы хотите мгновенно проверить элемент или его несуществование, но вы также не можете этого сделать.

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

Ответ 4

A kotlin версия ответа https://stackoverflow.com/users/503060/hedley:

clickWhenReady("#suggest",10,driver)

с помощью

fun clickWhenReady(selector: String,timeout: Long, webdriver: WebDriver?) {
    val wait = WebDriverWait(webdriver, timeout);
    val element = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(selector)));
    element.click();
}

Ответ 5

Я написал небольшой метод в С#, используя класс WebDriverWait. Отлично работает для меня.

public static void WaitForAjaxElement(IWebDriver driver, By byElement, double timeoutSeconds)
{
  WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutSeconds));
  wait.Until(x => x.FindElement(byElement));
}

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

WaitForAjaxElement(driver, By.ClassName("ui-menu-item"), 10);

Надеюсь, что это поможет.

Ответ 6

От Seleniumhq.com:

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

Если вы разместите свой тестовый код, что вы на самом деле хотите сделать, я могу предоставить дополнительную информацию.

Ответ 7

У меня есть другое решение для решения этой проблемы (только для IE, я никогда не пытаюсь использовать другой браузер):

1) после создания экземпляра драйвера Selenium вы можете получить его экземпляр COM экземпляра

Add-Type -Path .\SePSX.NET35\WebDriver.dll
$ieDriver = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"

$ieShell = $null

$shell_apps = (New-Object -ComObject Shell.Application).Windows()
foreach($app in $shell_apps)
{
    if ($app.LocationURL -eq $ieDriver.URL)
    {
        $ieShell = $app
        break
    }
}

if ($ieShell -eq $null)
{
    throw "Can't get WebDriver IE Instance"
}

2) после каждого вызова GotoURL или действия щелчка, проверьте состояние $ieShell.Busy, он будет ждать, пока страница не будет загружена.

$ieDriver.Navigate().GotoUrl("www.google.com")
while ($ieShell.Busy -eq $true) {sleep 1}   

then call Selenium driver to get element id and do the further action

$ieDriver.FindElementById ...

используйте этот способ, вам не нужно устанавливать загрузку страницы и findElement таймаут для Selenium

Ответ 8

import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;


FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver);
            wait.pollingEvery(250,  TimeUnit.MILLISECONDS);
            wait.withTimeout(20, TimeUnit.SECONDS);
            wait.ignoring(NoSuchElementException.class);

            Predicate<WebDriver> predicate  = new Predicate <WebDriver>()
                    {
                        public boolean apply(WebDriver arg0) {
                            WebElement element = arg0.findElement(By.id("colorVar"));
                            String color = element.getAttribute("color");
                            System.out.println("The color if the button is " + color);
                            if(color.equals("blue"))
                            {
                                return true;
                            }
                            return false;
                        }
                    };

            wait.until(predicate);

Ответ 9

Ниже приведен код кода эквивалента для ожидания ожидания в С#.Net с использованием DefaultWait.

         IWait<IWebDriver> wait = new DefaultWait<IWebDriver>(driver);
         wait.Timeout = TimeSpan.FromSeconds(10);
         wait.PollingInterval = TimeSpan.FromMilliseconds(100);

        IWebElement elementt = wait.Until<IWebElement>(ExpectedConditions.ElementIsVisible(By.Id("selectedfirstlast1")));
        SelectElement se = new SelectElement(driver.FindElement(By.Id("selectedfirstlast1")));
        element = se.SelectedOption;              
            if (element.Text.Contains("Mumbai") && element.Selected)
                driver.FindElement(By.XPath("//table/tbody/tr[2]/td[7]/a")).Click();