Attendre le chargement de la page dans le sélénium
Comment faire sélénium 2.0 attendez que la page se charge?
30 réponses
vous pouvez aussi 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"));
Utilisation de la classe WebDriverWait
Voir aussi ici
vous pouvez Vous attendre à montrer certains de l'élément. quelque chose comme dans 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 méthode findElement
sur un élément que vous prévoyez être sur la page chargée, le WebDriver Pollera pour cet élément jusqu'à ce qu'il trouve l'élément ou atteigne la valeur time out.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
source: implicite-waits
en général, avec Selenium 2.0, le pilote web ne doit retourner le contrôle au code appelant qu'une fois qu'il a déterminé que la page a été chargée. Si ce n'est pas le cas , vous pouvez appeler waitforelemement
, qui tourne autour de l'appel findelement
jusqu'à ce qu'il soit trouvé ou times out (time out peut être défini).
Ruby mise en œuvre:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
vous pouvez supprimer la ligne System.out
. 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");
}
});
}
vous pouvez également utiliser la classe: ExpectedConditions
pour attendre explicitement qu'un élément apparaisse sur la page Web avant que vous ne puissiez prendre des mesures autres actions
vous pouvez utiliser la classe ExpectedConditions
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.
toutes ces solutions sont acceptables pour des cas spécifiques, mais elles souffrent d'au moins un des deux problèmes possibles:
-
Ils ne sont pas assez génériques -- ils veulent vous connaître, à l'avance, qu'une condition spécifique sera vrai de la page, vous allez (par exemple, un élément sera affiché)
-
ils sont ouverts à une condition de course où vous utilisez un élément qui est réellement présent sur l'ancienne page, ainsi que la nouvelle page.
voici ma tentative d'une solution générique qui évite ce problème (en Python):
tout d'abord, une fonction "wait" Générique (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 selenium enregistre un numéro d'identification (interne) pour tous les éléments d'une page, y compris l'élément de premier niveau <html>
. Lorsqu'un page mise à jour ou charge, il obtient un nouvel élément html avec un nouvel ID.
donc, en supposant que vous voulez 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 de Pythonic, réutilisable, aide Générique, vous pouvez faire 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 alors vous pouvez l'utiliser sur à peu près n'importe quelle interaction de 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'en pensez-vous?
Plus d'info dans un blog post à ce sujet ici
si vous voulez attendre qu'un élément spécifique se charge, vous pouvez utiliser la méthode isDisplayed()
sur un 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: Les 5 Minutes Guide de mise en route )
Imran réponse du rabâchage 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 limitation sérieuse de WebDriver. Évidemment, attendre un élément n'implique pas que la page soit chargée, en particulier le DOM peut être entièrement construit (état onready) où JS est toujours en cours d'exécution et CSS et images sont toujours en cours de chargement.
je crois que la solution la plus simple est de mettre une variable JS sur l'événement onload après que tout soit initialisé et de vérifier et d'attendre cette variable JS dans le sélénium.
je suis surpris que les prédicats n'étaient pas le premier choix car vous savez généralement quel(s) élément (s) vous allez interagir ensuite sur la page que vous attendez de charger. Mon approche a toujours été de construire des prédicats/fonctions comme waitForElementByID(String id)
et waitForElemetVisibleByClass(String className)
, etc. et puis utilisez et réutilisez ceux-ci partout 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 d'essai:
driverWait.until(textIsPresent("expectedText");
dans ma classe d'essai parent:
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 à maintes reprises pour vous et l'intervalle de la fréquence de vérification peuvent être définies à l'ultime temps d'attente avant d'expirer. De plus, vous réutiliserez ces méthodes.
dans cet exemple, la classe mère a défini et déclenché les classes WebDriver driver
et WebDriverWait driverWait
.
j'espère que cela aidera.
Utiliser implicitement attendre attendre de chaque élément sur la page jusqu'à ce moment donné.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
cette attente pour chaque élément sur la page pendant 30 secondes.
une autre attente est explicitement une attente ou une attente conditionnelle dans cette attente jusqu'à ce que l'État soit donné.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
dans l'id donner l'id de l'élément statique qui est affiché avec méfiance sur la page, dès que la page est chargée.
attendre explicitement ou une attente conditionnelle dans cette attente jusqu'à l'état donné.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
cela attendra chaque élément web pendant 60 secondes.
Utiliser implicitement attendre attendre de chaque élément sur la page jusqu'à ce moment donné.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
cela attendra chaque élément web pendant 60 secondes.
/**
* 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 en cours de modification.
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 à vous utilisez-le :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
vous pouvez explicitement attendre qu'un élément apparaisse sur la page Web avant de pouvoir prendre n'importe quelle action (comme élément.cliquez sur())
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 ça marche très bien.
Ma manière simple:
long timeOut = 5000;
long end = System.currentTimeMillis() + timeOut;
while (System.currentTimeMillis() < end) {
if (String.valueOf(
((JavascriptExecutor) driver)
.executeScript("return document.readyState"))
.equals("complete")) {
break;
}
}
la meilleure façon d'attendre le chargement d'une page lors de l'utilisation des reliures Java pour WebDriver est d'utiliser le motif de conception de la Page Object avec PageFactory. Cela vous permet d'utiliser le AjaxElementLocatorFactory
qui, pour le dire simplement, les actes mondial attendre pour tous vos éléments. Il a des limites sur les éléments tels que les drop-boxes ou les transitions javascript complexes, mais il réduira drastiquement la quantité de code nécessaire et accélérera les temps de test. Un bon exemple peut être trouvé dans ce blogpost. Base la compréhension de Java de base est supposée.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
NodeJS Solution:
Dans Nodejs vous pouvez l'obtenir via des promesses...
Si vous écrivez ce code, vous pouvez être sûr que la page est complètement chargée lorsque vous arrivez à l'époque...
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 Sélénium de la documentation:
ce.get (url ) → Thenable
planifie une commande pour naviguer vers L'URL donnée.
renvoie une promesse qui sera résolue lorsque le document aura chargement terminé .
vous pouvez utiliser la méthode existante ci-dessous pour définir l'Heure de pageeLoadTimeout dans l'exemple ci-dessous si la page prend plus de 20 secondes à charger, alors il lancera une exception de page recharger
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
vous pouvez utiliser wait. il y a essentiellement 2 types d'attente dans le sélénium
- attente implicite
- attente explicite
- attente implicite
C'est très simple s'il vous plaît voir la syntaxe ci-dessous:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- attente explicite
attendre explicitement ou conditionnel dans cette attente jusqu'à compte tenu de la condition se produit.
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()
fonction Appel ci-dessous
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
driver.asserts().assertElementFound("Page was not loaded",
By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT);
Le plus simple est d'attendre juste pour quelques élément qui apparaîtra sur la page chargée.
si vous souhaitez cliquer sur un bouton déjà après que la page est chargée, vous pouvez utiliser attendre et cliquer:
await().until().at.most(20, TimeUnit.Seconds).some_element.isDisplayed(); // or another condition
getDriver().find(some_element).click;
Comment obtenir le Sélénium attendre pour le chargement de la page après un clic prévoit ce qui suit approche intéressante:
- conservez une référence à un
WebElement
provenant de l'ancienne page. - cliquez sur le lien.
- continuer à invoquer les opérations sur le
WebElement
jusqu'à ce queStaleElementReferenceException
soit lancé.
code échantillon:
WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});
utiliser une condition si et pour l'un des éléments présents
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
vous pouvez essayer ce code pour laisser la page se charger complètement jusqu'à ce que l'élément soit trouvé.
public void waitForBrowserToLoadCompletely() {
String state = null;
String oldstate = null;
try {
System.out.print("Waiting for browser loading to complete");
int i = 0;
while (i < 5) {
Thread.sleep(1000);
state = ((JavascriptExecutor) driver).executeScript("return document.readyState;").toString();
System.out.print("." + Character.toUpperCase(state.charAt(0)) + ".");
if (state.equals("interactive") || state.equals("loading"))
break;
/*
* If browser in 'complete' state since last X seconds. Return.
*/
if (i == 1 && state.equals("complete")) {
System.out.println();
return;
}
i++;
}
i = 0;
oldstate = null;
Thread.sleep(2000);
/*
* Now wait for state to become complete
*/
while (true) {
state = ((JavascriptExecutor) driver).executeScript("return document.readyState;").toString();
System.out.print("." + state.charAt(0) + ".");
if (state.equals("complete"))
break;
if (state.equals(oldstate))
i++;
else
i = 0;
/*
* If browser state is same (loading/interactive) since last 60
* secs. Refresh the page.
*/
if (i == 15 && state.equals("loading")) {
System.out.println("\nBrowser in " + state + " state since last 60 secs. So refreshing browser.");
driver.navigate().refresh();
System.out.print("Waiting for browser loading to complete");
i = 0;
} else if (i == 6 && state.equals("interactive")) {
System.out.println(
"\nBrowser in " + state + " state since last 30 secs. So starting with execution.");
return;
}
Thread.sleep(4000);
oldstate = state;
}
System.out.println();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
private static void checkPageIsReady(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
// Initially bellow given if condition will check ready state of page.
if (js.executeScript("return document.readyState").toString().equals("complete")) {
System.out.println("Page Is loaded.");
return;
}
// This loop will rotate for 25 times to check If page Is ready after
// every 1 second.
// You can replace your value with 25 If you wants to Increase or
// decrease wait time.
for (int i = 0; i < 25; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
// To check page ready state.
if (js.executeScript("return document.readyState").toString().equals("complete")) {
break;
}
}
}
vous pouvez utiliser cet extrait de code pour la page à charger:
IWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver,TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
ou vous pouvez utiliser serveur pour tout élément à charger et devenir visible / cliquable sur cette page, très probablement qui va être chargé à la fin du chargement comme:
Wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpathOfElement));
var element = GlobalDriver.FindElement(By.XPath(xpathOfElement));
var isSucceededed = element != null;