Comment forcer Selenium WebDriver à cliquer sur un élément qui n'est actuellement pas visible?

99

J'utilise l'API Java Selenium 2 avec FirefoxDriver. Lorsque je remplis un formulaire, des cases à cocher sont ajoutées à la page en fonction des entrées du formulaire.

Je voudrais simuler un clic sur ces cases à cocher en utilisant Selenium. Les éléments sont visibles et utilisables dans un navigateur ordinaire mais, sélénium affirme que les éléments ne sont pas visibles.

"Element is not currently visible and so may not be interacted with"

Puis-je forcer le sélénium à ignorer l'état non visible des éléments? Comment puis-je forcer Selenium à interagir avec l'élément non visible?

Djondal
la source
Quel navigateur utilisez-vous? Vous ne pouvez pas interagir avec des éléments désactivés ou non visibles, car un utilisateur final ne pourrait pas interagir avec eux. Vous devrez fournir votre code de test et la source de la page si vous souhaitez que je tente de diagnostiquer le problème.
Ardesco

Réponses:

102

Selenium détermine qu'un élément est visible ou non par les critères suivants (utilisez un inspecteur DOM pour déterminer ce que css s'applique à votre élément, assurez-vous de regarder le style calculé):

  • visibilité! = caché
  • display! = none (est également vérifié par rapport à chaque élément parent)
  • opacity! = 0 (ceci n'est pas vérifié en cliquant sur un élément)
  • la hauteur et la largeur sont toutes deux> 0
  • pour une entrée, le type d'attribut! = hidden

Votre élément correspond à l'un de ces critères. Si vous n'avez pas la possibilité de modifier le style de l'élément, voici comment vous pouvez le faire avec force avec javascript (en supposant WebDriver puisque vous avez dit API Selenium2):

((JavascriptExecutor)driver).executeScript("arguments[0].checked = true;", inputElement);

Mais cela ne déclenchera pas d'événement javascript, si vous dépendez de l'événement de modification pour cette entrée, vous devrez également le déclencher (de nombreuses façons de le faire, le plus simple est d'utiliser la bibliothèque javascript chargée sur cette page).

La source du contrôle de visibilité -

https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/dom.js#L577

La spécification WebDriver qui définit cela -

https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#widl-WebElement-isDisplayed-boolean

Lukeis
la source
1
Avez-vous une source (ou un lien canonique) pour la liste des conditions?
mjs
2
Tant que vous pouvez lire Javascript, la méthode bot.dom.isShown est ce qui détermine la visibilité: code.google.com/p/selenium/source/browse/trunk/javascript/atoms/…
lukeis
qu'est-ce que inputElement ici. Je lance le code ci-dessous WebElement inputElement = driver.findElement (By.xpath (PASSWORD_PATH)); (Pilote (JavascriptExecutor)) .executeScript ("arguments [0] .checked = true;", inputElement); Mais pas d'aide inputElement.sendKeys (mot de passe);
Deepak Goel
2
@NIleshSharma python a la méthode execute_script directement sur l'objet pilote lui-même: driver.execute_script (...)
lukeis
1
Le lien source publié par @TunaBum est devenu code.google.com/p/selenium/source/browse/javascript/atoms/…
Shepmaster
27

Parfois, cela signifie qu'il y a plusieurs éléments sur une page qui ont la même propriété que vous essayez de rechercher et que vous "parlez au mauvais".

Si votre élément ne peut pas être identifié de manière unique par: id ou: name (ou: class), cela pourrait être délicat.

Parfois, la recherche de l'élément par le: xpath aidera et dans certains cas même ce n'est pas pratique.

Dans ces cas, vous devrez peut-être obtenir tous les éléments qui correspondent à vos critères et référencer le bon par l'index. C'est sale, mais ça marche.

J'utilise Selenium / Watir de l'application Ruby on Rails, donc dans mon cas, l'exemple serait:

browser = Watir::Browser.new(:firefox, :profile => "default")       
browser.goto("http://www.google.com/analytics")
# login
browser.divs(:text, "+ New Property").last.click

J'espère que cela t'aides.

ranktrackerpro
la source
l'ajout d'un identifiant à l'élément dom l'a corrigé pour moi
naoru
J'ai eu le même problème et ajuster le XPath pour qu'il puisse distinguer un élément unique a fait l'affaire.
JohnL
J'ai eu le même problème. Changement de l'appel à findElements () pour compter les correspondances et il y avait un autre élément correspondant. Merci!
Bélier
Tant pis pour moi. Assurez-vous TOUJOURS que vos critères de sélection sont suffisamment spécifiques à l'élément avec lequel vous pensez interagir. Plusieurs fois, j'ai eu deux éléments en jeu et l'un est caché et me donne cette erreur.
Chris le
14

J'ai eu un problème similaire, mais il était lié au fait que l'élément n'était pas visible dans la fenêtre. J'ai pris une capture d'écran et j'ai réalisé que la fenêtre du navigateur était trop étroite et que l'élément ne pouvait pas être vu. J'ai fait un de ceux-ci et cela a fonctionné:

driver.maximize_window()

Voir: WebDriver.maximize_window ()

mynameistechno
la source
7

Ou vous pouvez utiliser Selenium Action Class pour simuler l'interaction de l'utilisateur - Par exemple

    WebDriver = new FirefoxDriver();

    WebElement menu = driver.findElement(By.xpath("")); // the triger event element

    Actions build = new Actions(driver); // heare you state ActionBuider
    build.moveToElement(menu).build().perform(); // Here you perform hover mouse over the needed elemnt to triger the visibility of the hidden
    WebElement m2m= driver.findElement(By.xpath(""));//the previous non visible element
    m2m.click();
fil mihaylov
la source
7

Il existe également un autre cas où l'élément visible sera reconnu comme non visible:

  • Lorsque l'élément est transformé en CSS
  • Lorsque l'élément parent de l'élément est transformé en CSS

Afin de vérifier si l'élément avec lequel vous ne souhaitez pas interagir est transformé en CSS, sur CHROME, procédez comme suit:

  1. inspecteur ouvert
  2. Trouver un élément intéressant (ou plus probablement son élément parent, soi-disant élément div)
  3. Sélectionnez l'onglet "Calculé"
  4. s'il y a un paramètre: webkit-transform: matrix (...) cela signifie que l'élément est transformé en CSS, et peut ne pas être reconnu par le sélénium 2 comme un élément visible
justnpT
la source
2

J'ai eu le même problème avec le sélénium 2 dans Internet Explorer 9, mais ma solution est vraiment étrange. Je n'ai pas pu cliquer sur les entrées de mon formulaire -> répétitions de sélénium, elles ne sont pas visibles.

Cela s'est produit lorsque ma forme avait des ombres courbes -> http://www.paulund.co.uk/creating-different-css3-box-shadows-effects : dans le concret "Effet n ° 2"

Je n'ai aucune idée, pourquoi et comment cette solution de pseudo-élément a arrêté les tests de sélénium, mais cela fonctionne pour moi.

Agoreddah
la source
2

Vous ne pouvez pas forcer l'accès / le changement d'élément auquel l'utilisateur n'a normalement pas accès, car Selenium est conçu pour imiter l'interaction de l'utilisateur.

Si cette erreur se produit, vérifiez si:

  • élément est visible dans votre fenêtre, essayez de maximiser la fenêtre actuelle que Webdriver utilise (par exemple maximize()dans node.js ,maximize_window() en Python),
  • votre élément n'apparaît pas deux fois (sous le même sélecteur), et vous sélectionnez le mauvais,
  • si votre élément est masqué, pensez à le rendre visible,
  • si vous souhaitez accéder / modifier la valeur de l'élément caché malgré la limitation, utilisez Javascript pour cela (par exemple executeScript()dans node.js , execute_script()en Python).
Kenorb
la source
1
Je n'avais aucune idée que Selenium était conçu pour être aussi strict. Il semble que ce ne soit pas vraiment un outil d'automatisation au sens général, mais plutôt un outil d'interaction utilisateur automatisé. Cela a un peu de sens, je suppose. Merci de clarifier!
Daniel Lidström
1

Je viens de résoudre cette erreur en utilisant capybara dans le projet ror en ajoutant:

Capybara.ignore_elements = true

à features/support/env.rb.

Zernel
la source
1

Je viens de résoudre cette erreur en attendant la propriété d'affichage de l'élément

waitFor() { element.displayed }
Suat Keskin
la source
De toutes les réponses sur cette page, c'est ce qui a résolu mon problème avec une boîte de dialogue Bootstrap Modal. Merci @Suat Keskin!
alastairs
1

J'entre dans l'exception ElementNotVisibleException en utilisant du sélénium pour des tests fonctionnels sur un site django avec des glyphicons bootstrap comme liens dans des modèles comme:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger"></span></a>

Lors de mes tests fonctionnels, le style bootstrap n'est pas chargé, puis essayer de cliquer sur de tels liens lèvera ElementNotVisibleException. J'arrive à les rendre cliquables en ajoutant simplement un espace dans le tag, comme ça:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger">&nbsp;</span></a>
jean pierre huart
la source
1

Il y a beaucoup de bonnes réponses sur cette page.

  1. Je commence généralement par maxim.window (), en fait je le fais dans l'usine de pilotes ou partout où vous initialisez votre pilote. C'est quelque chose de fait par défaut - toujours.
  2. C'est généralement une attente d'élément en raison d'un certain retard javascript.

Les deux sont discutés dans divers détails ci-dessus. La réponse que je n'ai pas vue était ScrollToElement. Il semble que vous traitez une liste d'éléments, tandis que vous créez plus d'éléments, des cases à cocher. Cela peut entraîner le déplacement d'éléments de votre liste hors de la page visible. Parfois, vous pouvez voir l'élément à l'œil nu, mais vous ne pouvez tout simplement pas cliquer dessus. Lors du traitement de listes, vous devez parfois interrompre le défilement.

  • Définissez un point de rupture et vérifiez si l'élément que vous utilisez se trouve au bord de la fenêtre, en haut / en bas à droite / à gauche. Parfois, lorsque c'est le cas, vous ne pouvez pas y accéder via le sélénium, mais vous pouvez cliquer manuellement avec votre souris.

Parce que je rencontre cela, j'ai créé un PageScroll.java et y ai placé mes scripts de défilement. Voici quelques-unes des méthodes de cette classe:

public static void scrollToTop(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0,0)");
    }

    public static void scrollToBottom(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0, document.body.scrollHeight)");
    }

    public static void scrollToElementTop(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(true);", element);
    }

    public static void scrollToElementBottom(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(false);", element);
    }

voir Faire défiler l'élément dans la vue avec sélénium pour plus d'exemples

mancocapac
la source
0

La réponse acceptée a fonctionné pour moi. Vous trouverez ci-dessous un code pour trouver l'élément parent qui fait croire à Selenium qu'il n'est pas visible.

function getStyles(element){
	
	computedStyle = window.getComputedStyle(element);

	if(computedStyle.opacity === 0
	|| computedStyle.display === "none"
	|| computedStyle.visibility === "hidden"
	|| (computedStyle.height < 0 && computedStyle.height < 0)
	|| element.type === "hidden") {
		console.log("Found an element that Selenium will consider to not be visible")
		console.log(element);
		console.log("opacity: " + computedStyle.opacity);
		console.log("display: " + computedStyle.display);
		console.log("visibility: " + computedStyle.visibility);
		console.log("height: " + computedStyle.height);
		console.log("width: " + computedStyle.width);
	}

	if(element.parentElement){
		getStyles(element.parentElement);
	}
}

getStyles(document.getElementById('REPLACE WITH THE ID OF THE ELEMENT YOU THINK IS VISIBLE BUT SELENIUM CAN NOT FIND'));

starmer
la source
0

Pour ajouter mon grain de sable ici: si un élément réside derrière un div fixe, il sera considéré comme non visible et vous ne pourrez pas cliquer dessus; cela m'est arrivé récemment et je l'ai résolu en exécutant un script comme recommandé ci-dessus, ce qui fait:

document.evaluate("<xpath locator for element to be clicked>", document, null, XPathResult.ANY_TYPE, null).iterateNext().click()", locator);
Fernando Gabrieli
la source
Qu'est-ce que le localisateur ici?
Anjana