web-dev-qa-db-fra.com

Comment vérifier si un élément est visible avec WebDriver

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?

62
ponzao

element instanceof RenderedWebElement devrait marcher.

20
hleinone

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.

131
sleske

J'ai les 2 manières suggérées suivantes:

  1. Vous pouvez utiliser isDisplayed() comme ci-dessous:

    driver.findElement(By.id("idOfElement")).isDisplayed();
    
  2. 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")));
15
Ripon Al Wasim

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
7
Christopher Bales

Réponse courte: utilisez #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();

Contrôle de visibilité personnalisé exécuté sur le client

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

  • il a un opacity> 0
  • la propriété display est définie sur autre chose que none
  • le visibility prop est défini sur visible
  • il n'y a pas d'autres éléments qui le cachent (c'est l'élément le plus haut)

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']"));
    }
}
4
oligofren

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)

2
Jason

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;
    }
1
Adnan Ghaffar