Comment faire attendre Selenium 2.0 pour que la page se charge?
Comment faire attendre Selenium 2.0 pour que la page se charge?
Réponses:
Vous pouvez également vérifier pageloaded en utilisant le code suivant
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"));
Utiliser la classe WebDriverWait
Voir aussi ici
Vous pouvez vous attendre à montrer un élément. quelque chose comme en C #:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));
Si vous définissez l'attente implicite du pilote, puis appelez la findElement
méthode sur un élément que vous attendez sur la page chargée, le WebDriver interrogera cet élément jusqu'à ce qu'il trouve l'élément ou atteigne la valeur de délai d'expiration.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
source: implicit-waits
En général, avec Selenium 2.0, le pilote Web ne doit retourner le contrôle du code appelant qu'après avoir déterminé que la page a été chargée. Si ce n'est pas le cas, vous pouvez appeler waitforelemement
, qui fait un cycle d'appel findelement
jusqu'à ce qu'il soit trouvé ou expire (le délai peut être défini).
If click() causes a new page to be loaded via an event or is done by sending a native event (which is a common case on Firefox, IE on Windows) then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.
JavascriptExecutor
, en attendant que document.readyState soit "complet". En raison de l'aller-retour du sélénium au navigateur, les conditions de concurrence sont atténuées, je suppose, et cela "toujours" fonctionne pour moi. Après "click ()" quand je m'attends à ce qu'une page se charge, j'attends explicitement (en utilisant WebDriverWait) le readystate. ]
Implémentation de Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Vous pouvez supprimer la System.out
ligne. Il est ajouté à des fins de débogage.
WebDriver driver_;
public void waitForPageLoad() {
Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}
Toutes ces solutions conviennent à des cas spécifiques, mais elles souffrent d'au moins l'un des deux problèmes possibles:
Ils ne sont pas assez génériques - ils veulent que vous sachiez, à l'avance, qu'une condition spécifique sera vraie pour la page que vous allez visiter (par exemple, un élément sera affiché)
Ils sont ouverts à une condition de concurrence où vous utilisez un élément qui est réellement présent sur l'ancienne page ainsi que sur la nouvelle page.
Voici ma tentative d'une solution générique qui évite ce problème (en Python):
Tout d'abord, une fonction générique "wait" (utilisez un WebDriverWait si vous le souhaitez, je les trouve moches):
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__))
Ensuite, la solution repose sur le fait que le sélénium enregistre un numéro d'identification (interne) pour tous les éléments d'une page, y compris l' <html>
élément de niveau supérieur . Lorsqu'une page est actualisée ou chargée, elle obtient un nouvel élément html avec un nouvel ID.
Donc, en supposant que vous vouliez cliquer sur un lien avec le texte "mon lien" par exemple:
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)
Pour plus d'aide générique Pythonique, réutilisable, vous pouvez créer un gestionnaire de contexte:
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)
Et puis vous pouvez l'utiliser sur à peu près n'importe quelle interaction au sélénium:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Je pense que c'est pare-balles! Qu'est-ce que tu penses?
Plus d'informations dans un blog à ce sujet ici
Vous pouvez également utiliser la classe: ExpectedConditions
pour attendre explicitement qu'un élément apparaisse sur la page Web avant de pouvoir entreprendre toute autre action
Vous pouvez utiliser la ExpectedConditions
classe pour déterminer si un élément est visible:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
Voir ExpectedConditions class Javadoc
pour la liste de toutes les conditions que vous pouvez vérifier.
La réponse d'Imran retravaillée pour Java 7:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState"
).equals("complete");
}
});
Cela semble être une sérieuse limitation de WebDriver. Évidemment, attendre un élément n'impliquera pas le chargement de la page, en particulier le DOM peut être entièrement construit (état déjà prêt) par lequel JS est toujours en cours d'exécution et CSS et les images sont toujours en cours de chargement.
Je crois que la solution la plus simple consiste à définir une variable JS lors de l'événement onload après que tout est initialisé et à vérifier et attendre cette variable JS dans Selenium.
Si vous souhaitez attendre le chargement d'un élément spécifique, vous pouvez utiliser la isDisplayed()
méthode sur RenderedWebElement
:
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
(Exemple tiré du Guide de démarrage en 5 minutes )
RenderedWebElement
en a pas dans l'API. Cependant, la isDisplayed()
méthode est désormais disponible directement sur WebElement
.
Attendez explicitement ou attendez conditionnellement dans cette attente jusqu'à ce que cette condition soit donnée.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Cela attendra chaque élément Web pendant 60 secondes.
Utilisez attendre implicitement l'attente de chaque élément de la page jusqu'à ce moment donné.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Cela attendra chaque élément Web pendant 60 secondes.
Utilisez implicitement l'attente de chaque élément de la page jusqu'à l'heure donnée.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
cette attente pour chaque élément sur la page pendant 30 secondes.
Une autre attente est Attendre explicitement ou attendre conditionnellement dans cette attente jusqu'à la condition donnée.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Dans id, donnez l'ID d'élément statique qui s'affiche différemment sur la page, dès que la page est chargée.
Je suis surpris que les prédicats ne soient pas le premier choix, car vous savez généralement avec quels éléments vous allez ensuite interagir sur la page que vous attendez pour charger. Mon approche a toujours été de créer des prédicats / fonctions comme waitForElementByID(String id)
et waitForElemetVisibleByClass(String className)
, etc., puis de les utiliser et de les réutiliser là où j'en ai besoin, que ce soit pour un chargement de page ou un changement de contenu de page que j'attends.
Par exemple,
Dans ma classe de test:
driverWait.until(textIsPresent("expectedText");
Dans mon parent de classe de test:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
Bien que cela semble beaucoup, il prend soin de vérifier à plusieurs reprises pour vous et l'intervalle de fréquence de vérification peut être défini avec le temps d'attente ultime avant la fin du délai. De plus, vous réutiliserez ces méthodes.
Dans cet exemple, la classe parente a défini et lancé le WebDriver driver
et le WebDriverWait driverWait
.
J'espère que ça aide.
La meilleure façon d'attendre le chargement des pages lors de l'utilisation des liaisons Java pour WebDriver est d'utiliser le modèle de conception d'objet de page avec PageFactory. Cela vous permet d'utiliser le AjaxElementLocatorFactory
qui pour le mettre agit simplement comme une attente globale pour tous vos éléments. Il a des limites sur des éléments tels que des boîtes de dépôt ou des transitions javascript complexes, mais il réduira considérablement la quantité de code nécessaire et accélérera les temps de test. Un bon exemple peut être trouvé dans ce blog. Une compréhension de base de Core Java est supposée.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Solution NodeJS:
Dans Nodejs, vous pouvez l'obtenir via des promesses ...
Si vous écrivez ce code, vous pouvez être sûr que la page est entièrement chargée lorsque vous arrivez à la ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Si vous écrivez ce code, vous naviguerez et le sélénium attendra 3 secondes ...
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...
De la documentation Selenium:
this.get (url) → Thénable
Planifie une commande pour naviguer vers l'URL donnée.
Renvoie une promesse qui sera résolue une fois le chargement du document terminé .
Voici une version Java 8 de la réponse actuellement la plus appréciée :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Où myDriver
est un WebDriver
objet (déclaré plus tôt).
Remarque : sachez que cette méthode ( document.readyState
) vérifie uniquement le DOM.
Appelez ci-dessous Fonction dans votre script, cela attendra que la page ne soit pas chargée en utilisant javascript
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}
/**
* Call this method after an event that will change the page.
*
* @see #beforePageLoad
*
* Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}
Vous pouvez passer du document à un élément, dans le cas où seule une partie d'un document est modifiée.
Cette technique a été inspirée par la réponse de Sincebasic.
SeleniumWaiter :
import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaiter {
private WebDriver driver;
public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
Et pour vous l' utiliser :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Vous pouvez utiliser la méthode existante ci-dessous pour définir le temps de pageeLoadTimeout dans l'exemple ci-dessous si la page prend plus de 20 secondes à charger, alors il lèvera une exception de rechargement de page
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Vous pouvez explicitement attendre qu'un élément apparaisse sur la page Web avant de pouvoir entreprendre une action (comme element.click ())
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
C'est ce que j'ai utilisé pour un scénario similaire et cela fonctionne très bien.
La meilleure façon que j'ai vue est d'utiliser le stalenessOf
attendue, d'attendre que l'ancienne page devienne périmée.
Exemple:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Il faudra attendre dix secondes pour que l'ancienne balise HTML devienne périmée, puis lèvera une exception si cela ne se produit pas.
J'utilise node + selenium-webdriver (dont la version est maintenant 3.5.0). ce que je fais pour cela est:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Vous pouvez utiliser l'attente. il y a essentiellement 2 types d'attente dans le sélénium
- Attente implicite
C'est très simple, veuillez consulter la syntaxe ci-dessous:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Attente explicite
Attendez explicitement ou attendez conditionnellement dans cette attente jusqu'à ce qu'une condition donnée se produise.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Vous pouvez utiliser d'autres propriétés comme visblityOf()
,visblityOfElement()
Si quelqu'un utilise du séléniure:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Plus de conditions peuvent être trouvées ici: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
Dans mon cas, j'ai utilisé ce qui suit pour connaître l'état de chargement de la page. Dans notre application, des gifs de chargement sont présents et je les écoute comme suit pour éliminer les temps d'attente indésirables dans le script.
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
Où le xpath localise le gif dans le DOM HTML. Après cela, vous pouvez également implémenter vos méthodes d'action Cliquez sur.
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
Man toutes ces réponses nécessitent trop de code. Cela devrait être une chose simple car c'est assez courant.
Pourquoi ne pas simplement injecter du javascript simple avec le pilote Web et vérifier. C'est la méthode que j'utilise dans ma classe Webscraper. Le javascript est assez basique même si vous ne connaissez pas js.
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state.
More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
Comment faire pour que Selenium attende le chargement de la page après un clic fournit l'approche intéressante suivante:
WebElement
de l'ancienne page.WebElement
jusqu'à ce que StaleElementReferenceException
soit lancé.Exemple de code:
WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
.