J'espère que ce n'est que moi, mais Selenium Webdriver semble être un cauchemar complet. Le pilote Web Chrome est actuellement inutilisable et les autres pilotes ne sont pas assez fiables, du moins il semble. Je suis aux prises avec de nombreux problèmes, mais en voici un.
Au hasard, mes tests échoueront avec un
"org.openqa.selenium.StaleElementReferenceException: Element is no longer attached
to the DOM
System info: os.name: 'Windows 7', os.arch: 'amd64',
os.version: '6.1', java.version: '1.6.0_23'"
J'utilise les versions 2.0b3 de Webdriver. J'ai vu cela se produire avec les pilotes FF et IE. La seule façon d'éviter cela est d'ajouter un appel réel Thread.sleep
avant que l'exception ne se produise. C'est une solution de contournement médiocre, donc j'espère que quelqu'un pourra signaler une erreur de ma part qui améliorera tout cela.
java
selenium-webdriver
webdriver
automated-tests
Ray Nicholus
la source
la source
from selenium.common.exceptions import NoSuchElementException
Réponses:
Oui, si vous rencontrez des problèmes avec StaleElementReferenceExceptions, c'est parce que vos tests sont mal écrits. C'est une condition de course. Considérez le scénario suivant:
Désormais, au moment où vous cliquez sur l'élément, la référence d'élément n'est plus valide. Il est presque impossible pour WebDriver de faire une bonne estimation de tous les cas où cela pourrait se produire - il lève donc les mains et vous donne le contrôle, qui en tant qu'auteur du test / de l'application devrait savoir exactement ce qui peut ou non se produire. Ce que vous voulez faire est d'attendre explicitement que le DOM soit dans un état où vous savez que les choses ne changeront pas. Par exemple, en utilisant un WebDriverWait pour attendre qu'un élément spécifique existe:
La méthode presenceOfElementLocated () ressemblerait à ceci:
Vous avez tout à fait raison sur le fait que le pilote Chrome actuel est assez instable, et vous serez heureux d'apprendre que le tronc Selenium a un pilote Chrome réécrit, où la plupart de l'implémentation a été effectuée par les développeurs Chromium dans le cadre de leur arbre.
PS. Alternativement, au lieu d'attendre explicitement comme dans l'exemple ci-dessus, vous pouvez activer les attentes implicites - de cette façon, WebDriver bouclera toujours jusqu'au délai spécifié d'attente pour que l'élément devienne présent:
D'après mon expérience, l'attente explicite est toujours plus fiable.
la source
com.google.common.base.Function<F, T>
fourni par Guava .J'ai pu utiliser une méthode comme celle-ci avec un certain succès:
Oui, il continue d'interroger l'élément jusqu'à ce qu'il ne soit plus considéré comme périmé (frais?). Cela ne va pas vraiment à la racine du problème, mais j'ai trouvé que le WebDriver peut être assez pointilleux pour lancer cette exception - parfois je l'obtiens, et parfois non. Ou il se pourrait que le DOM change vraiment.
Je ne suis donc pas tout à fait d'accord avec la réponse ci-dessus selon laquelle cela indique nécessairement un test mal rédigé. Je l'ai sur de nouvelles pages avec lesquelles je n'ai en aucune façon interagi. Je pense qu'il y a une certaine fragilité dans la façon dont le DOM est représenté, ou dans ce que WebDriver considère comme obsolète.
la source
J'obtiens parfois cette erreur lorsque les mises à jour AJAX sont à mi-chemin. Capybara semble être assez intelligent pour attendre les changements du DOM (voir Pourquoi wait_until a été supprimé de Capybara ), mais le temps d'attente par défaut de 2 secondes n'était tout simplement pas suffisant dans mon cas. Changé dans _spec_helper.rb_ avec eg
la source
J'étais confronté au même problème aujourd'hui et j'ai créé une classe wrapper, qui vérifie avant chaque méthode si la référence de l'élément est toujours valide. Ma solution pour récupérer l'élément est assez simple, alors j'ai pensé que je voulais simplement la partager.
Vous voyez je "localise" ou plutôt enregistre l'élément dans une variable js globale et récupère l'élément si nécessaire. Si la page est rechargée, cette référence ne fonctionnera plus. Mais tant que seuls des changements sont apportés pour vaincre, la référence demeure. Et cela devrait faire l'affaire dans la plupart des cas.
Cela évite également de rechercher à nouveau l'élément.
John
la source
J'ai eu le même problème et le mien était causé par une ancienne version au sélénium. Je ne peux pas mettre à jour vers une version plus récente en raison de l'environnement de développement. Le problème est dû à HTMLUnitWebElement.switchFocusToThisIfNeeded (). Lorsque vous accédez à une nouvelle page, il se peut que l'élément sur lequel vous avez cliqué sur l'ancienne page soit le
oldActiveElement
(voir ci-dessous). Selenium essaie d'obtenir le contexte de l'ancien élément et échoue. C'est pourquoi ils ont construit un essai dans les versions futures.Code de la version du pilote selenium-htmlunit <2.23.0:
Code de la version selenium-htmlunit-driver> = 2.23.0:
Sans mettre à jour vers 2.23.0 ou une version plus récente, vous pouvez simplement donner n'importe quel élément sur le focus de la page. Je viens de l'utiliser
element.click()
par exemple.la source
Je viens de m'arriver en essayant d'envoyer des touches à une zone de saisie de recherche - qui a une mise à jour automatique en fonction de ce que vous tapez. Comme mentionné par Eero, cela peut arriver si votre élément fait une mise à jour d'Ajax pendant que vous tapez votre texte dans l'élément d'entrée . La solution consiste à envoyer un caractère à la fois et à rechercher à nouveau l'élément d'entrée . (Ex. En rubis illustré ci-dessous)
la source
Pour ajouter à la réponse de @ jarib, j'ai créé plusieurs méthodes d'extension qui aident à éliminer la condition de concurrence.
Voici ma configuration:
J'ai une classe appelée "Driver.cs". Il contient une classe statique pleine de méthodes d'extension pour le pilote et d'autres fonctions statiques utiles.
Pour les éléments que j'ai généralement besoin de récupérer, je crée une méthode d'extension comme celle-ci:
Cela vous permet de récupérer cet élément de n'importe quelle classe de test avec le code:
Maintenant, si cela aboutit à un
StaleElementReferenceException
, j'ai la méthode statique suivante dans ma classe de pilote:Le premier paramètre de cette fonction est toute fonction qui renvoie un objet IWebElement. Le deuxième paramètre est un timeout en secondes (le code du timeout a été copié à partir de Selenium IDE pour FireFox). Le code peut être utilisé pour éviter l'exception d'élément périmé de la manière suivante:
Le code ci-dessus appellera
driver.SpecificElementToGet().Displayed
jusqu'à ce qu'ildriver.SpecificElementToGet()
ne jette aucune exception et.Displayed
évalue àtrue
et 5 secondes ne se sont pas écoulées. Après 5 secondes, le test échouera.D'un autre côté, pour attendre qu'un élément ne soit pas présent, vous pouvez utiliser la fonction suivante de la même manière:
la source
Je pense que j'ai trouvé une approche pratique pour gérer StaleElementReferenceException. Habituellement, vous devez écrire des wrappers pour chaque méthode WebElement pour réessayer des actions, ce qui est frustrant et vous fait perdre beaucoup de temps.
Ajout de ce code
avant chaque action WebElement peut augmenter la stabilité de vos tests, mais vous pouvez toujours obtenir StaleElementReferenceException de temps en temps.
Voici donc ce que j'ai trouvé (en utilisant AspectJ):
Pour activer cet aspect, créez un fichier
src\main\resources\META-INF\aop-ajc.xml
et écrivezAjoutez ceci à votre
pom.xml
Et c'est tout. J'espère que ça aide.
la source
Vous pouvez résoudre ce problème en utilisant l'attente explicite afin de ne pas avoir à utiliser l'attente difficile.
Si vous récupérez tous les éléments avec une propriété et que vous l'itérez en utilisant pour chaque boucle, vous pouvez utiliser wait dans la boucle comme ceci,
ou pour un seul élément, vous pouvez utiliser le code ci-dessous,
la source
Dans Java 8, vous pouvez utiliser une méthode très simple pour cela:
la source
la source