Селен ждать, пока документ не будет готов

Может ли кто-нибудь дать мне, как я могу заставить селен ждать до момента полной загрузки страницы? Я хочу что-то общее, я знаю, что могу настроить WebDriverWait и называть что-то вроде "найти", чтобы заставить его подождать, но я не зашел так далеко. Мне просто нужно проверить, что страница загружается успешно и перейти на следующую страницу для проверки.

Я нашел что-то в .net, но не смог заставить его работать в java...

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

Любые мысли кто-нибудь?

Ответ 1

Попробуйте этот код:

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

Приведенный выше код будет ждать до 10 секунд для загрузки страницы. Если загрузка страницы превышает время, она выдаст TimeoutException. Вы ловите исключение и выполняете свои потребности. Я не уверен, завершает ли он загрузку страницы после сгенерированного исключения. я еще не пробовал этот код Хочешь просто попробовать.

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

См. документацию для WebDriver.Timeouts для получения дополнительной информации.

Ответ 2

Ваше предлагаемое решение только ждет DOM readyState для сигнала complete. Но Selenium по умолчанию пытается дождаться тех (и немного больше) на загрузке страницы через driver.get() и element.click(). Они уже блокируют, они ждут полной загрузки страницы, и они должны работать нормально.

Проблема, очевидно, заключается в перенаправлении через запросы AJAX и запущенные скрипты - они не могут быть захвачены Selenium, это не дожидаясь их завершения. Кроме того, вы не можете надежно их поймать через readyState - он ждет бит, который может быть полезен, но он будет сигнализировать complete задолго до того, как будет загружен контент AJAX.

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

Общее правило состоит в том, чтобы полагаться на WebDriver, чтобы сделать свою часть, затем использовать неявные ожидания, а затем использовать явные ожидания для элементов, которые вы хотите утверждать на странице, но есть намного больше методов, которые можно сделать. Вы должны выбрать один (или комбинацию нескольких из них), который лучше всего работает в вашем случае на вашей тестируемой странице.

См. мои два ответа относительно этого для получения дополнительной информации:

Ответ 3

Это рабочая версия Java примера, который вы дали:

void waitForLoad(WebDriver driver) {
    new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
            ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}

Пример для c #:

public static void WaitForLoad(IWebDriver driver, int timeoutSec = 15)
{
  IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
  WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
  wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}

Ответ 4

Здесь моя попытка полностью общего решения в Python:

Во-первых, общая функция "wait" (используйте WebDriverWait, если хотите, я нахожу их уродливыми):

def wait_for(condition_function):
    start_time = time.time()
    while time.time() < start_time + 3:
        if condition_function():
            return True
        else:
            time.sleep(0.1)
    raise Exception('Timeout waiting for {}'.format(condition_function.__name__))

Далее, решение основывается на том факте, что селен записывает (внутренний) id-номер для всех элементов на странице, включая элемент верхнего уровня <html>. Когда страница обновляется или загружается, она получает новый элемент html с новым идентификатором.

Итак, если вы хотите щелкнуть ссылку с текстом "моя ссылка", например:

old_page = browser.find_element_by_tag_name('html')

browser.find_element_by_link_text('my link').click()

def page_has_loaded():
    new_page = browser.find_element_by_tag_name('html')
    return new_page.id != old_page.id

wait_for(page_has_loaded)

Для более Pythonic, многоразового, общего помощника вы можете создать менеджер контекста:

from contextlib import contextmanager

@contextmanager
def wait_for_page_load(browser):
    old_page = browser.find_element_by_tag_name('html')

    yield

    def page_has_loaded():
        new_page = browser.find_element_by_tag_name('html')
        return new_page.id != old_page.id

    wait_for(page_has_loaded)

И тогда вы можете использовать его практически для любого взаимодействия селена:

with wait_for_page_load(browser):
    browser.find_element_by_link_text('my link').click()

Я считаю, что пуленепробиваемый! Как вы думаете?

Дополнительная информация в сообщении в блоге об этом здесь

Ответ 5

У меня была аналогичная проблема. Мне нужно было подождать, пока мой документ будет готов, но также до тех пор, пока все вызовы Ajax не закончились. Второе условие оказалось трудно обнаружить. В конце я проверил активные вызовы Ajax и работал.

JavaScript:

return (document.readyState == 'complete' && jQuery.active == 0)

Полный метод С#:

private void WaitUntilDocumentIsReady(TimeSpan timeout)
{
    var javaScriptExecutor = WebDriver as IJavaScriptExecutor;
    var wait = new WebDriverWait(WebDriver, timeout);            

    // Check if document is ready
    Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor
        .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
    wait.Until(readyCondition);
}

Ответ 6

WebDriverWait wait = new WebDriverWait(dr, 30);
wait.until(ExpectedConditions.jsReturnsValue("return document.readyState==\"complete\";"));

Ответ 7

Для С# NUnit вам нужно преобразовать WebDriver в JSExecuter, а затем выполнить script, чтобы проверить, завершено ли состояние document.ready или нет. Проверьте код для справки:

 public static void WaitForLoad(IWebDriver driver)
    {
        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
        int timeoutSec = 15;
        WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
        wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
    }

Это будет ждать выполнения условия или таймаута.

Ответ 8

Для начальной загрузки страницы я заметил, что "Максимизация" окна браузера практически ждет завершения загрузки страницы (включая источники)

Заменить:

AppDriver.Navigate().GoToUrl(url);

С

public void OpenURL(IWebDriver AppDriver, string Url)
            {
                try
                {
                    AppDriver.Navigate().GoToUrl(Url);
                    AppDriver.Manage().Window.Maximize();
                    AppDriver.SwitchTo().ActiveElement();
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERR: {0}; {1}", e.TargetSite, e.Message);
                    throw;
                }
            }

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

OpenURL(myDriver, myUrl);

Это приведет к загрузке страницы, дождитесь завершения, максимизации и сосредоточения на ней. Я не знаю, почему это так, но это работает.

Если вы хотите дождаться загрузки страницы после щелчка по следующему или любому другому движку навигации по страницам, кроме "Навигация" (), ответ Ben Dyer (в этом потоке) выполнит эту работу.

Ответ 9

Посмотрите tapestry веб-фреймворк. Вы можете скачать исходный код там.

Идея состоит в том, чтобы сигнализировать, что страница готова с помощью атрибута html тела. Вы можете использовать эту идею, игнорируя сложные случаи судебного разбирательства.

<html>
<head>
</head>
<body data-page-initialized="false">
    <p>Write you page here</p>

    <script>
    $(document).ready(function () {
        $(document.body).attr('data-page-initialized', 'true');
    });
    </script>  
</body>
</html>

И затем создайте расширение Selenium webdriver (в соответствии с рамкой гобелена)

public static void WaitForPageToLoad(this IWebDriver driver, int timeout = 15000)
{
    //wait a bit for the page to start loading
    Thread.Sleep(100);

    //// In a limited number of cases, a "page" is an container error page or raw HTML content
    // that does not include the body element and data-page-initialized element. In those cases,
    // there will never be page initialization in the Tapestry sense and we return immediately.
    if (!driver.ElementIsDisplayed("/html/body[@data-page-initialized]"))
    {                
        return;
    }

    Stopwatch stopwatch = Stopwatch.StartNew();

    int sleepTime = 20;

    while(true)
    {
        if (driver.ElementIsDisplayed("/html/body[@data-page-initialized='true']"))
        {
            return;
        }

        if (stopwatch.ElapsedMilliseconds > 30000)
        {
            throw new Exception("Page did not finish initializing after 30 seconds.");
        }

        Thread.Sleep(sleepTime);
        sleepTime *= 2; // geometric row of sleep time
    }          
}

Используйте расширение ElementIsDisplayed написанное Алистером Скоттом.

public static bool ElementIsDisplayed(this IWebDriver driver, string xpath)
{
    try
    {
        return driver.FindElement(By.XPath(xpath)).Displayed;
    }
    catch(NoSuchElementException)
    {
        return false;
    }
}

И, наконец, создадим тест:

driver.Url = this.GetAbsoluteUrl("/Account/Login");            
driver.WaitForPageToLoad();

Ответ 10

Ответ Бен-Дьер не скомпилировался на моей машине ("The method until(Predicate<WebDriver>) is ambiguous for the type WebDriverWait").

Рабочая версия Java 8:

Predicate<WebDriver> pageLoaded = wd -> ((JavascriptExecutor) wd).executeScript(
        "return document.readyState").equals("complete");
new FluentWait<WebDriver>(driver).until(pageLoaded);

Версия Java 7:

Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {

        @Override
        public boolean apply(WebDriver input) {
            return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
        }

};
new FluentWait<WebDriver>(driver).until(pageLoaded);

Ответ 11

Я пробовал этот код, и он работает для меня. Я вызываю эту функцию каждый раз, когда перехожу на другую страницу

public static void waitForPageToBeReady() 
{
    JavascriptExecutor js = (JavascriptExecutor)driver;

    //This loop will rotate for 100 times to check If page Is ready after every 1 second.
    //You can replace your if you wants to Increase or decrease wait time.
    for (int i=0; i<400; i++)
    { 
        try 
        {
            Thread.sleep(1000);
        }catch (InterruptedException e) {} 
        //To check page ready state.

        if (js.executeScript("return document.readyState").toString().equals("complete"))
        { 
            break; 
        }   
      }
 }

Ответ 12

В Nodejs вы можете получить его через promises...

Если вы напишете этот код, вы можете быть уверены, что страница будет полностью загружена, когда вы перейдете к...

driver.get('www.sidanmor.com').then(()=> {
    // here the page is fully loaded!!!
    // do your stuff...
}).catch(console.log.bind(console));

Если вы напишете этот код, вы будете перемещаться, а селен будет ждать 3 секунды...

driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...

Из документации Selenium:

this.get(url) → Thenable

Задает команду для перехода к указанному URL.

Возвращает обещание, которое будет разрешено, если документ имеет завершенную загрузку.

Документация селена (Nodejs)

Ответ 13

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

После некоторых поисков я нашел сообщение на Obay the test goat, у которого есть решение для этого проблема. Код С# для этого решения выглядит примерно так:

 IWebElement page = null;
 ...
 public void WaitForPageLoad()
 {
    if (page != null)
    {
       var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
       waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
    }

    var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));

    page = driver.FindElement(By.TagName("html"));

}

`  Я запускаю этот метод непосредственно после driver.navigate.gotourl, так что он получает ссылку на страницу как можно скорее. Получайте удовольствие от этого!

Ответ 14

Обычно, когда selenium открывает новую страницу с помощью метода click или submit или get, он будет ждать до тех пор, пока страница не будет загружена, но проблема в том, что когда на странице есть вызов xhr (ajax), он никогда не будет ждать загрузки xhr, поэтому Создание нового метода для мониторинга XHR и ждать их, это будет хорошо.

public boolean waitForJSandJQueryToLoad() {
    WebDriverWait wait = new WebDriverWait(webDriver, 30);
    // wait for jQuery to load
    ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
            Long r = (Long)((JavascriptExecutor)driver).executeScript("return $.active");
            return r == 0;
        } catch (Exception e) {
            LOG.info("no jquery present");
            return true;
        }
      }
    };

    // wait for Javascript to load
    ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        return ((JavascriptExecutor)driver).executeScript("return document.readyState")
        .toString().equals("complete");
      }
    };

  return wait.until(jQueryLoad) && wait.until(jsLoad);
}

if $.active == 0, поэтому нет активного вызова xhrs (который работает только с jQuery). для вызова javascript ajax вы должны создать переменную в вашем проекте и смоделировать ее.

Ответ 15

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

public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        driver.get("https://www.crowdanalytix.com/#home");
        WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk");
        int i = 1;
        while (webElement == null && i < 4) {
            webElement = getWebElement(driver, "homessssssssssss");
            System.out.println("calling");
            i++;
        }
        System.out.println(webElement.getTagName());
        System.out.println("End");
        driver.close();
    }

    public static WebElement getWebElement(WebDriver driver, String id) {
        WebElement myDynamicElement = null;
        try {
            myDynamicElement = (new WebDriverWait(driver, 10))
                    .until(ExpectedConditions.presenceOfElementLocated(By
                            .id(id)));
            return myDynamicElement;
        } catch (TimeoutException ex) {
            return null;
        }
    }

Ответ 16

Я выполнил код javascript, чтобы проверить, готов ли документ. Сэкономил мне много времени на отладку тестов на селен для сайтов с рендерингом на стороне клиента.

public static boolean waitUntilDOMIsReady(WebDriver driver) {
def maxSeconds = DEFAULT_WAIT_SECONDS * 10
for (count in 1..maxSeconds) {
    Thread.sleep(100)
    def ready = isDOMReady(driver);
    if (ready) {
        break;
    }
}

}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

Ответ 17

public boolean waitForElement(String zoneName, String element, int index, int timeout) {
        WebDriverWait wait = new WebDriverWait(appiumDriver, timeout/1000);
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(element)));
        return true;
    }

Ответ 18

Как пишет Rubanov для С#, я пишу его для Java, и это:

    public void waitForPageLoaded() {
    ExpectedCondition<Boolean> expectation = new
            ExpectedCondition<Boolean>() {
                public Boolean apply(WebDriver driver) {
                    return (((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete")&&((Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")));
                }
            };
    try {
        Thread.sleep(100);
        WebDriverWait waitForLoad = new WebDriverWait(driver, 30);
        waitForLoad.until(expectation);
    } catch (Throwable error) {
        Assert.fail("Timeout waiting for Page Load Request to complete.");
    }
}

Ответ 19

В Java это будет выглядеть ниже: -

  private static boolean isloadComplete(WebDriver driver)
    {
        return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
                || ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
    }

Ответ 20

Возможно, должен работать следующий код:

WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.presenceOfAllElementsLocated(By.xpath("//*")));

Ответ 21

Если у вас медленная страница или подключение к сети, есть вероятность, что ничего из вышеперечисленного не будет работать. Я перепробовал их все, и единственное, что сработало для меня, - это дождаться последнего видимого элемента на этой странице. Возьмите, например, веб-страницу Bing. Они разместили значок КАМЕРА (кнопка поиска по изображению) рядом с основной кнопкой поиска, которая отображается только после загрузки всей страницы. Если все это сделали, то все, что нам нужно сделать, это использовать явное ожидание, как в приведенных выше примерах.

Ответ 22

public void waitForPageToLoad()
  {
(new WebDriverWait(driver, DEFAULT_WAIT_TIME)).until(new ExpectedCondition<Boolean>() {
      public Boolean apply(WebDriver d) {
        return (((org.openqa.selenium.JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"));
      }
    });//Here DEFAULT_WAIT_TIME is a integer correspond to wait time in seconds

Ответ 23

Здесь что-то похожее, в Ruby:

wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { @driver.execute_script('return document.readyState').eql?('complete') }

Ответ 24

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

driver.get(homeUrl); 
Thread.sleep(5000);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord);
driver.findElement(By.xpath("Your_Xpath_here")).click();

Ответ 25

Я проверил страницу загрузки завершена, работа в Selenium 3.14.0

    public static void UntilPageLoadComplete(IWebDriver driver, long timeoutInSeconds)
    {
        Until(driver, (d) =>
        {
            Boolean isPageLoaded = (Boolean)((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete");
            if (!isPageLoaded) Console.WriteLine("Document is loading");
            return isPageLoaded;
        }, timeoutInSeconds);
    }

    public static void Until(IWebDriver driver, Func<IWebDriver, Boolean> waitCondition, long timeoutInSeconds)
    {
        WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
        webDriverWait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        try
        {
            webDriverWait.Until(waitCondition);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

Ответ 26

Для людей, которым нужно дождаться появления определенного элемента. (используется c #)

public static void WaitForElement(IWebDriver driver, By element)
{
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
    wait.Until(ExpectedConditions.ElementIsVisible(element));
}

Затем, если вы хотите подождать, например, если в DOM существует class= "error-message", вы просто делаете:

WaitForElement(driver, By.ClassName("error-message"));

Для идентификатора это будет

WaitForElement(driver, By.Id("yourid"));

Ответ 27

Используете ли вы Angular? Если возможно, что веб-сервер не распознает, что асинхронные вызовы завершены.

Я рекомендую посмотреть Paul Hammants ngWebDriver. Метод waitForAngularRequestsToFinish() может пригодиться.