Je travaille sur un Java Selenium-WebDriver. J'ai ajouté
driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
et
WebElement textbox = driver.findElement(By.id("textbox"));
car il faut quelques secondes à mes applications pour charger l'interface utilisateur. J'ai donc mis 2 secondes implicitwait. mais je suis incapable de localiser l'élément textbox
Puis j'ajoute Thread.sleep(2000);
Maintenant cela fonctionne bien. Lequel est un meilleur moyen?
Eh bien, il existe deux types d’attente: une attente explicite et une attente implicite. L'idée d'une attente explicite est
WebDriverWait.until(condition-that-finds-the-element);
Le concept d’attente implicite est
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Vous pouvez obtenir la différence dans les détails ici .
Dans de telles situations, je préférerais utiliser l'attente explicite (fluentWait
en particulier):
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;
};
La fonction fluentWait
renvoie votre élément Web trouvé . De la documentation sur fluentWait
: Une implémentation de l'interface Wait qui peut avoir son délai d'attente et son intervalle d'interrogation configurés à la volée . Chaque instance de FluentWait définit le temps nécessaire pour attendre une condition, ainsi que la fréquence à laquelle vérifier la condition. De plus, l'utilisateur peut configurer l'attente pour ignorer des types d'exceptions spécifiques pendant l'attente, tels que NoSuchElementExceptions lors de la recherche d'un élément sur la page. Détails vous pouvez obtenir ici
L'utilisation de fluentWait
dans votre cas soit la suivante:
WebElement textbox = fluentWait(By.id("textbox"));
Cette approche est meilleure à mon humble avis, car vous ne savez pas exactement combien de temps attendre et dans l'intervalle d'interrogation, vous pouvez définir une valeur temporelle arbitraire pour laquelle la présence de l'élément sera vérifiée par le biais de .
Si vous utilisez webdriverJs (node.js),
driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
driver.sleep(5000);
});
Le code ci-dessus fait que le navigateur attend 5 secondes après avoir cliqué sur le bouton.
Ce fil est un peu plus ancien, mais je pensais poster ce que je fais actuellement (travail en cours).
Bien que je sois toujours dans des situations où le système est lourdement chargé et que je clique sur un bouton d'envoi (par exemple, login.jsp), les trois conditions (voir ci-dessous) renvoient true
mais la page suivante (par exemple, home.jsp) n'a pas Vous n'avez pas encore commencé à charger.
Il s'agit d'une méthode d'attente générique qui prend une liste de ExpectedConditions.
public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
boolean isLoaded = false;
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(waitTimeInSec, TimeUnit.SECONDS)
.ignoring(StaleElementReferenceException.class)
.pollingEvery(2, TimeUnit.SECONDS);
for (ExpectedCondition<Boolean> condition : conditions) {
isLoaded = wait.until(condition);
if (isLoaded == false) {
//Stop checking on first condition returning false.
break;
}
}
return isLoaded;
}
J'ai défini diverses conditions attendues réutilisables (trois sont ci-dessous). Dans cet exemple, les trois conditions attendues sont document.readyState = 'complete', aucun «wait_dialog» n'est présent et aucun «spinners» (des éléments indiquant que des données asynchrones sont demandées).
Seul le premier peut être appliqué de manière générique à toutes les pages Web.
/**
* Returns 'true' if the value of the 'window.document.readyState' via
* JavaScript is 'complete'
*/
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
Boolean result;
try {
result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
} catch (Exception ex) {
result = Boolean.FALSE;
}
return result;
}
};
/**
* Returns 'true' if there is no 'wait_dialog' element present on the page.
*/
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
Boolean loaded = true;
try {
WebElement wait = driver.findElement(By.id("F"));
if (wait.isDisplayed()) {
loaded = false;
}
} catch (StaleElementReferenceException serex) {
loaded = false;
} catch (NoSuchElementException nseex) {
loaded = true;
} catch (Exception ex) {
loaded = false;
System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
}
return loaded;
}
};
/**
* Returns true if there are no elements with the 'spinner' class name.
*/
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
Boolean loaded = true;
try {
List<WebElement> spinners = driver.findElements(By.className("spinner"));
for (WebElement spinner : spinners) {
if (spinner.isDisplayed()) {
loaded = false;
break;
}
}
}catch (Exception ex) {
loaded = false;
}
return loaded;
}
};
En fonction de la page, je peux en utiliser un ou tous:
waitForPageLoad(timeoutInSec,
EXPECT_DOC_READY_STATE,
EXPECT_NOT_WAITING,
EXPECT_NO_SPINNERS
);
Il existe également des ExpectedConditions prédéfinies dans la classe suivante: org.openqa.Selenium.support.ui.ExpectedConditions
Utiliser Thread.sleep(2000);
est une attente inconditionnelle. Si votre test se charge plus rapidement, vous devrez toujours attendre. Donc, en principe, utiliser implicitlyWait
est la meilleure solution.
Cependant, je ne vois pas pourquoi implicitlyWait
ne fonctionne pas dans votre cas. Avez-vous mesuré si la findElement
prend réellement deux secondes avant de lancer une exception. Si tel est le cas, pouvez-vous essayer d'utiliser l'attente conditionnelle de WebDriver comme décrit dans this answer?
J'aime utiliser des conditions personnalisées. Voici du code en Python:
def conditions(driver):
flag = True
ticker = driver.find_elements_by_id("textbox")
if not ticker:
flag = False
return flag
... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)
Chaque fois que vous devez attendre, vous pouvez le faire explicitement en vérifiant l'existence d'un certain élément (cet élément peut varier d'une page à l'autre). find_elements_by_id
liste de retours - vide ou non, il vous suffit de vérifier.
clic semble être bloquant? - voici une autre façon d'attendre si vous utilisez WebDriverJS:
driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
driver.getPageSource().then(function(source) {
console.log(source);
});
});
Le code ci-dessus attend après le clic sur le bouton pour le chargement de la page suivante, puis saisit la source de la page suivante.
Thread.Sleep(5000);
Cela m’a aidé, mais l’exception InterruptedException doit être traitée . Il est donc préférable de l’entourer de try and catch:
try {
Thread.Sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
OR
Ajouter une déclaration de jets:
public class myClass {
public static void main(String[] args) throws InterruptedException
{ ... }
Je préférerais le second car on peut alors utiliser sleep()
autant de fois que nécessaire et éviter la répétition des blocs try
et catch
à chaque fois que l'on utilise sleep()
.
Parfois, l'attente implicite échoue, en disant qu'un élément existe mais qu'il n'en a pas.
La solution consiste à éviter d'utiliser driver.findElement et à la remplacer par une méthode personnalisée qui utilise implicitement une attente explicite. Par exemple:
import org.openqa.Selenium.NoSuchElementException;
public WebElement element(By locator){
Integer timeoutLimitSeconds = 20;
WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
try {
wait.until(ExpectedConditions.presenceOfElementLocated(locator));
}
catch(TimeoutException e){
throw new NoSuchElementException(locator.toString());
}
WebElement element = driver.findElement(locator);
return element;
}
Il existe d'autres raisons d'éviter des attentes implicites autres que des défaillances sporadiques et occasionnelles (voir this link ).
Vous pouvez utiliser cette méthode "element" de la même manière que driver.findElement. Par exemple:
driver.get("http://yoursite.html");
element(By.cssSelector("h1.logo")).click();
Si vous voulez vraiment attendre quelques secondes pour le dépannage ou une autre occasion rare, vous pouvez créer une méthode de pause similaire à celle proposée par Selenium IDE:
public void pause(Integer milliseconds){
try {
TimeUnit.MILLISECONDS.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Implicitement wait et Thread.sleep Les deux sont utilisés uniquement pour la synchronisation ... mais la différence est que nous pouvons utiliser implicitement attendre l'intégralité du programme, mais Thread.sleep fonctionnera uniquement pour ce code unique ... Voici ma suggestion: utiliser Attendre implicitement une fois dans le programme quand à chaque fois que votre page Web sera rafraîchie, vous utiliserez Thread.sleep à ce moment-là ... ce sera beaucoup mieux :)
Voici mon code:
package beckyOwnProjects;
import Java.util.concurrent.TimeUnit;
import org.openqa.Selenium.By;
import org.openqa.Selenium.WebDriver;
import org.openqa.Selenium.WebElement;
import org.openqa.Selenium.firefox.FirefoxDriver;
import org.openqa.Selenium.interactions.Actions;
public class Flip {
public static void main(String[] args) throws InterruptedException {
WebDriver driver=new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
driver.get("https://www.flipkart.com");
WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
Actions act=new Actions(driver);
Thread.sleep(5000);
act.moveToElement(ele).perform();
}
}
Parfois, l'attente implicite semble être annulée et le temps d'attente est raccourci. [@ eugene.polschikov] possédait une bonne documentation sur les pourquoi. J'ai trouvé dans mes tests et le codage avec Selenium 2 que les attentes implicites sont bonnes mais qu'il faut parfois attendre explicitement.
Il est préférable d'éviter d'appeler directement un fil pour s'endormir, mais parfois, il n'y a pas de solution. Cependant, il existe d’autres options d’attente qui aident Selenium. waitForPageToLoad et waitForFrameToLoad se sont révélés particulièrement utiles.
Réponse : attendez quelques secondes avant que la visibilité de l'élément à l'aide de Selenium WebDriver ne passe par les méthodes ci-dessous.
implicitlyWait () : L'instance WebDriver attend le chargement complet de la page. Vous avez besoin de 30 à 60 secondes pour attendre le chargement complet de la page.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
ExplicitlyWait WebDriverWait () : l'instance WebDriver attend le chargement complet de la page.
WebDriverWait wait = new WebDriverWait(driver, 60);
wait.until(ExpectedConditions.visibilityOf(textbox));
driver.findElement(By.id("Year")).sendKeys(allKeys);
Remarque : Veuillez utiliser ExplicitlyWait WebDriverWait () pour gérer un élément WebElement particulier.
Attente implicite: pendant l'attente implicite si le pilote Web ne peut pas le trouver immédiatement en raison de sa disponibilité, WebDriver attendra l'heure indiquée et n'essaiera pas de retrouver l'élément pendant la période spécifiée. Une fois la durée spécifiée écoulée, le système essaiera de rechercher à nouveau l'élément une dernière fois avant de lancer une exception. Le réglage par défaut est zéro. Une fois que nous avons défini une heure, le pilote Web attend la période de l'instance d'objet WebDriver.
Attente explicite: Il peut y avoir des cas où un élément particulier prend plus d'une minute à charger. Dans ce cas, vous n'aimez certainement pas définir un délai énorme pour l'attente implicite, car si vous faites cela, votre navigateur attendra le même temps pour chaque élément . l'élément requis uniquement. En suivant ceci, le temps d'attente implicite de votre navigateur serait court pour chaque élément et important pour un élément spécifique.