2013-02-27 3 views
95

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

Я нашел кое-что в .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")); 

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

+0

Почему, что вы не хотите использовать ждать? – Amey

+6

Вы имеете в виду явное ожидание? Это занимает много времени, я тестирую несколько 10 тыс. Страниц. – Girish

+1

Я имею в виду, добавление исправления ожидания может быть не очень хорошей идеей, если я тестирую большое количество ссылок, не так ли? – Girish

ответ

61

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

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

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

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

Для более info.

+3

Спасибо, так что происходит здесь, если страница загружается до 10 секунд , будет ли еще ждать 10 секунд для выполнения следующей строки после загрузки? – Girish

+0

Нет, если ваша страница загружается до 10 секунд, означает, что она прекратит условие ожидания и выполнит предыдущую строку. – Manigandan

+3

Это используется, когда вы ожидаете загрузки страниц, которые тоже длинный тайм-аут и исключение броска, он не сразу ждет загрузки страницы или устанавливает более эффективную политику загрузки. По умолчанию используется бесконечное время, поэтому ваши загрузки страниц никогда не бросают исключения, а Selenium всегда пытается дождаться их загрузки c ompletely. –

48

Это работает 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(this IWebDriver driver, int timeoutSec = 15) 
{   
    WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec)); 
    wait.Until(wd => wd.ExecuteScript("return document.readyState") == "complete");   
} 
+1

Чувак, я копирую/вставляю это. Этот фрагмент просто блестящий. Почему я об этом не думал? Правда, что более чем одна пара глазных яблок всегда приводит к хорошему решению. Благодарю. –

+2

Вы можете поместить это в Java 1.7 версии Compatable, как лямбда-выражения не поддерживает – vkrams

+3

Java 1.7 версии: wait.until (новый Predicate () { общественных булево применить (WebDriver драйвер) { возвращения ((JavascriptExecutor) драйвер) .executeScript («return document.readyState»). равен («полный»); } } ); – luQ

75

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

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

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

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

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

+17

Это неточно, Selenium не ждет и не блокирует вызовы 'element.click()'. – hwjp

+2

@ hwjp Ухаживать за подробностями? [В JavaDocs говорится иначе] (https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/WebElement.html#click%28%29): _ «Если это вызывает новую страницу для загрузки этот метод будет пытаться заблокировать, пока страница не загрузится ». _ –

+3

cf некоторые [беседы, которые у меня были в списке рассылки] (https://groups.google.com/forum/#!topic/selenium- разработчики/hA_jTx4vrDM) кажется, что это неточно. selenium может блокировать вызовы .get, где вы явно запрашиваете URL-адрес, но он не делает ничего особенного при вызовах кликов, потому что он не может определить, нажали ли вы на «настоящую» гиперссылку или на ту, которая будет перехвачена javascript. .. – hwjp

-1
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 
0

Вы можете написать некоторую логику, чтобы справиться с этим.У меня написать метод, который будет возвращать 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; 
     } 
    } 
9

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

во-первых, общая функция «ожидание» (используйте 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-number для всех элементов на странице, включая элемент верхнего уровня <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) 

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

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() 

Я считаю, что это Булла TProof! Как вы думаете?

Более подробная информация в blog post about it here

+0

Очень интересный подход. Одна из проблем заключается в том, может ли это работать при начальной загрузке страницы после запуска браузера. Нет никакой гарантии, что в исходном состоянии браузера загружена любая страница. Кроме того, в Java я не вижу, что у нас есть «id» на объекте. Я предполагаю, что вы не имеете в виду, что селен вставляет атрибут html id. Я добавлю еще один ответ на этот вопрос, как только я рассмотрю этот вариант. Спасибо за сообщение! – Lukus

+0

@hwjp Я использую это решение много раз с отличными результатами, но похоже, что он не работает в одном случае. Полное объяснение проблемы http://stackoverflow.com/q/31985739/4249707 –

-1

Вот что-то подобное, в Ruby:

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

Ваш код не работает для меня. Как мне включить iframe и ждать onload = "javascript: pageload(); functionPageLoad();" перезагрузить страницу в Ruby? Я обнаружил, что открываю iframe внутри страницы, у меня есть к ней доступ, затем перезагрузка страницы, и я больше не могу получить доступ к кадру. Я прочитал много ответов, касающихся ожидания, сна, времени, переключения на кадр, затем на родителя, однако я не могу достичь своей цели. –

+1

Похоже, ваш вопрос в первую очередь связан с тем, как переключиться на iFrame, а не на ожидание загрузки документа. Возможно, было бы лучше начать новый вопрос, если вы не сможете найти решение в вопросе о работе с iFrames. – emery

2

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

Заменить:

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

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

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

5

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

Javascript:

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

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

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

Посмотрите tapestry веб-рамки. Вы можете там download source code.

Идея состоит в том, чтобы сигнализировать, что страница готова с помощью атрибута 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 written by Alister Scott.

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(); 
-2

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

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(); 
4

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

1

Ответ Ben Dryer не скомпилирован на моей машине ("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); 
0

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

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"); 
} 
0

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

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

В Nodejs вы можете получить его с помощью обещаний ...

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

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... 

С Селен документации:

this.get (URL) → Thenable

Планирует команды, чтобы перейти к данному URL.

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

Selenium Documentation (Nodejs)

-3

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

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

+0

Он очень не использовал Угловое. Этот ответ был занижен, потому что, похоже, вы не внимательно прочитали исходный вопрос. – zelusp

+0

Но не подпускайте голоса, выгибаете вас из формы. Люди здесь хорошо. И критика на самом деле является формой любви (потому что, если кто-то требует времени, чтобы исправить кого-то, это потому, что они заботятся). Оформить заказ [Как задавать вопросы умным способом] (http://www.catb.org/~esr/faqs/smart-questions.html#stackoverflow) - эти идеи также применяются для ответа на вопросы умным способом. – zelusp

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

Для C# NUnit, вам нужно конвертировать WebDriver в JSExecuter, а затем выполнить скрипт для проверки состояния 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"); 
    } 

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

1

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

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

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, так что он получает ссылку на страницу как можно скорее. Получайте удовольствие от этого!

0

Как Рубанов писал для C#, я пишу это для 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."); 
    } 
} 
0

В Java это будет, как показано ниже: -

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

Было бы лучше объединить команды JS в один, чтобы вам не приходилось дважды ударять страницу, например. 'return document.readyState == 'loaded' || return document.readyState == 'complete'' – JeffC

0

нормально, когда селен открыть новую страницу из нажмите или отправьте или получите методы, он будет ждать, пока страница не будет загружена, но проблема в том, что на странице есть вызов xhr (ajax), он никогда не будет ждать загрузки xhr, поэтому создание нового метода для мониторинга xhr и ждать их будет хорошо. (Извините мой плохой английский: D)

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

если $ .active == 0, так что это не активный XHR следует не созывать (эту работу только с JQuery). для javascript ajax call вам нужно создать переменную в своем проекте и имитировать ее.

0

Следующий код должен работать, вероятно:

WebDriverWait wait = new WebDriverWait(driver, 10); 
wait.until(ExpectedConditions.presenceOfAllElementsLocated(By.xpath("//*"))); 
Смежные вопросы