Avec WebDriver
de Selenium 2.0a2, je ne parviens pas à vérifier si un élément est visible.
WebDriver.findElement
retourne un WebElement
qui, malheureusement, n’offre pas de méthode isVisible
. Je peux faire le tour en utilisant WebElement.clear
ou WebElement.click
_ qui jettent un ElementNotVisibleException
, mais cela semble très sale.
De meilleures idées?
element instanceof RenderedWebElement
devrait marcher.
Même si je suis un peu en retard pour répondre à la question:
Vous pouvez maintenant utiliser WebElement.isDisplayed()
pour vérifier si un élément est visible.
Remarque :
Un élément peut être invisible pour de nombreuses raisons. Selenium tente de couvrir la plupart d’entre eux, mais il existe des cas Edge où cela ne fonctionne pas comme prévu.
Par exemple, isDisplayed()
renvoie le résultat false
si un élément contient display: none
ou opacity: 0
, mais au moins dans mon test, il ne détecte pas de manière fiable si un élément est couvert par un autre en raison du positionnement CSS.
J'ai les 2 manières suggérées suivantes:
Vous pouvez utiliser isDisplayed()
comme ci-dessous:
driver.findElement(By.id("idOfElement")).isDisplayed();
Vous pouvez définir une méthode comme indiqué ci-dessous et l'appeler:
public boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
}
catch (org.openqa.Selenium.NoSuchElementException e) {
return false;
}
}
Maintenant, vous pouvez faire l'assertion comme ci-dessous pour vérifier si l'élément est présent ou non:
assertTrue(isElementPresent(By.id("idOfElement")));
Si vous utilisez C #, ce serait driver.Displayed. Voici un exemple de mon propre projet:
if (!driver.FindElement(By.Name("newtagfield")).Displayed) //if the tag options is not displayed
driver.FindElement(By.Id("expand-folder-tags")).Click(); //make sure the folder and tags options are visible
#visibilityOfElementLocated
Aucune des réponses utilisant isDisplayed
ou similaire est correcte. Ils vérifient seulement si la propriété display
n'est pas none
, pas si l'élément est réellement visible! Selenium avait un tas de méthodes utilitaires statiques ajoutées dans la classe ExpectedConditions
. Deux d'entre eux peuvent être utilisés dans ce cas:
Utilisation
@Test
// visibilityOfElementLocated has been statically imported
public demo(){
By searchButtonSelector = By.className("search_button");
WebDriverWait wait = new WebDriverWait(driver, 10);
driver.get(homeUrl);
WebElement searchButton = wait.until(
visibilityOfElementLocated
(searchButtonSelector));
//clicks the search button
searchButton.click();
C'était ma réponse avant de découvrir les méthodes utilitaires sur ExpectedConditions
. Cela reste peut-être pertinent, car je suppose qu'il en fait plus que la méthode susmentionnée, qui vérifie uniquement que l'élément a une hauteur et une largeur.
En substance: on ne peut répondre à cela par Java et le findElementBy*
méthodes et WebElement#isDisplayed
seul, car ils ne peuvent vous dire que si un élément existe, pas s'il est réellement visible. Le PO n'a pas défini ce que signifie visible, mais cela implique normalement
opacity
> 0display
est définie sur autre chose que none
visibility
prop est défini sur visible
La plupart des gens incluraient également l'exigence que cela se trouve réellement dans la fenêtre d'affichage (pour qu'une personne puisse la voir).
Pour une raison quelconque, ce besoin tout à fait normal n’est pas satisfait par l’API pure Java, tandis que les interfaces frontales de Selenium qui le construit implémentent souvent une variante de isVisible
, qui est: pourquoi je savais que cela devrait être possible. Et après avoir parcouru la source du Node framework WebDriver.IO j'ai trouvé la source de isVisible
, qui est maintenant renommé sous le nom plus approprié de isVisibleInViewport
dans la version 5.0-bêta.
Fondamentalement, ils implémentent la commande personnalisée en tant qu'appel qui délègue à un javascript qui s'exécute sur le client et effectue le travail réel! C'est le bit "serveur":
export default function isDisplayedInViewport () {
return getBrowserObject(this).execute(isDisplayedInViewportScript, {
[ELEMENT_KEY]: this.elementId, // w3c compatible
ELEMENT: this.elementId // jsonwp compatible
})
}
Le bit intéressant est donc le javascript envoyé pour s'exécuter sur le client:
/**
* check if element is visible and within the viewport
* @param {HTMLElement} elem element to check
* @return {Boolean} true if element is within viewport
*/
export default function isDisplayedInViewport (elem) {
const dde = document.documentElement
let isWithinViewport = true
while (elem.parentNode && elem.parentNode.getBoundingClientRect) {
const elemDimension = elem.getBoundingClientRect()
const elemComputedStyle = window.getComputedStyle(elem)
const viewportDimension = {
width: dde.clientWidth,
height: dde.clientHeight
}
isWithinViewport = isWithinViewport &&
(elemComputedStyle.display !== 'none' &&
elemComputedStyle.visibility === 'visible' &&
parseFloat(elemComputedStyle.opacity, 10) > 0 &&
elemDimension.bottom > 0 &&
elemDimension.right > 0 &&
elemDimension.top < viewportDimension.height &&
elemDimension.left < viewportDimension.width)
elem = elem.parentNode
}
return isWithinViewport
}
Ce morceau de JS peut en fait être copié (presque) mot pour mot dans votre propre base de code (remove export default
et remplacez const
par var
dans le cas de navigateurs non persistants)! Pour l'utiliser, lisez-le de File
dans un String
pouvant être envoyé par Selenium pour être exécuté sur le client.
Un autre script intéressant et connexe qui mérite d'être étudié est selectByVisibleText .
Si vous n'avez pas encore exécuté JS avec Selenium, vous pourriez avoir n aperçu de ceci ou parcourir les API JavaScriptExecutor .
En général, essayez de toujours utiliser des scripts asynchrones non bloquants (c'est-à-dire # executeAsyncScript ), mais comme nous avons déjà un script synchrone bloquant, nous pouvons également utiliser l'appel de synchronisation normal. L'objet renvoyé peut être constitué de plusieurs types d'objet, il est donc préférable de le lancer. Cela pourrait être une façon de le faire:
/**
* Demo of a Java version of webdriverio's isDisplayedInViewport
* https://github.com/webdriverio/webdriverio/blob/v5.0.0-beta.2/packages/webdriverio/src/commands/element/isDisplayedInViewport.js
* The super class GuiTest just deals with setup of the driver and such
*/
class VisibleDemoTest extends GuiTest {
public static String readScript(String name) {
try {
File f = new File("Selenium-scripts/" + name + ".js");
BufferedReader reader = new BufferedReader( new FileReader( file ) );
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
} catch(IOError e){
throw new RuntimeError("No such Selenium script: " + f.getAbsolutePath());
}
}
public static Boolean isVisibleInViewport(RemoteElement e){
// according to the Webdriver spec a string that identifies an element
// should be deserialized into the corresponding web element,
// meaning the 'isDisplayedInViewport' function should receive the element,
// not just the string we passed to it originally - how this is done is not our concern
//
// This is probably when ELEMENT and ELEMENT_KEY refers to in the wd.io implementation
//
// Ref https://w3c.github.io/webdriver/#dfn-json-deserialize
return js.executeScript(readScript("isDisplayedInViewport"), e.getId());
}
public static Boolean isVisibleInViewport(String xPath){
driver().findElementByXPath("//button[@id='should_be_visible']");
}
@Test
public demo_isVisibleInViewport(){
// you can build all kinds of abstractions on top of the base method
// to make it more Selenium-ish using retries with timeouts, etc
assertTrue(isVisibleInViewport("//button[@id='should_be_visible']"));
assertFalse(isVisibleInViewport("//button[@id='should_be_hidden']"));
}
}
Il est important de voir si l'élément est visible ou non comme le Driver.FindElement
vérifiera uniquement la source HTML. Mais le code popup pourrait être dans la page HTML, et ne pas être visible. Donc, Driver.FindElement
fonction renvoie un faux positif (et votre test échouera)
Vérification ele est visible.
public static boolean isElementVisible(final By by)
throws InterruptedException {
boolean value = false;
if (driver.findElements(by).size() > 0) {
value = true;
}
return value;
}