Ich habe eine Liste mit mehreren Links unter jedem Abschnitt. Jeder Abschnitt hat die gleichen Links, die ich brauche, um unter jedem Abschnitt auf einen bestimmten Link zu klicken. Ich habe den folgenden Code geschrieben, aber wenn er ausgeführt wird, gibt er mir einen stale element reference: element is not attached to the page document
Fehler.
Das ist mein Code:
public static void main(String[] args) throws InterruptedException
{
WebDriver driver = new ChromeDriver();
driver.navigate().to("url......");
driver.findElement(By.id("Login1_txtEmailID")).sendKeys("[email protected]");
driver.findElement(By.id("Login1_txtPassword")).sendKeys("Testing1*");
driver.findElement(By.id("Login1_btnLogin")).click();
List<WebElement> LeftNavLinks=driver.findElements(By.xpath("//*[@id='sliding-navigation']//a"));
Thread.sleep(1000);
String ben="Benefit Status";
String[] linkTexts = new String[LeftNavLinks.size()];
int i = 0;
for (WebElement e : LeftNavLinks)
{
linkTexts[i] = e.getText();
System.out.print(i+" " + linkTexts[i]+"\n");
if(linkTexts[i].equals(ben))
{
String BenefitStatLi="//*[@id='sliding-navigation']/li[%s]/a";
System.out.print(i+" " + linkTexts[i]+"\n");
driver.findElement(By.xpath(String.format(BenefitStatLi,i))).click();
driver.findElement(By.xpath("//* [@id='divContentHolder']/div[1]/a[1]")).click();
}
i++;
}
}
}
Dies ist die HTML-Struktur wie folgt
<div id="ucAdminMenu_divMenu">
<ul id="sliding-navigation">
<li class="sliding-element">
<a href=" ">Claims Status</a>
</li>
<li class="sliding-element">
<a href=" ">Eligibility Status</a>
</li>
<li class="sliding-element">
<h3>Section-1</h3>
</li>
<li class="sliding-element">
<a href=" ">Forms and Documents</a>
</li>
<li class="sliding-element">
<a href=" HourBank.aspx?id=002">Hour Bank</a>
</li>
<li class="sliding-element">
<h3>Section-2</h3>
</li>
<li class="sliding-element">
<a href=" ">Benefit Status</a>
</li>
<li class="sliding-element">
<a href=" ">Forms and Documents</a>
</li>
<li class="sliding-element">
<h3>Section-3</h3>
</li>
<li class="sliding-element">
<a href=" ">Forms and Documents</a>
</li>
<li class="sliding-element">
<h3>Testing Fund</h3>
</li>
<li class="sliding-element">
<a href=" ">Benefit Status</a>
</li>
<li class="sliding-element">
<a href=" ">Order ID Card</a>
</li>
</ul>
</div>
Die Fehlerverfolgung lautet:
Exception in thread "main"
org.openqa.selenium.StaleElementReferenceException: stale element
reference: element is not attached to the page document
quelle
Wenn Sie auf dieses Problem stoßen, definieren Sie das Webelement einfach erneut über der Zeile, in der ein Fehler angezeigt wird.
Beispiel:
WebElement button = driver.findElement(By.xpath("xpath")); button.click(); //here you do something like update or save //then you try to use the button WebElement again to click button.click();
Da sich das DOM z. B. durch die Aktualisierungsaktion geändert hat, wird ein
StaleElementReference
Fehler angezeigt.Lösung:
WebElement button = driver.findElement(By.xpath("xpath")); button.click(); //here you do something like update or save //then you define the button element again before you use it WebElement button1 = driver.findElement(By.xpath("xpath")); //that new element will point to the same element in the new DOM button1.click();
quelle
Um damit umzugehen, verwende ich die folgende Klickmethode. Dadurch wird versucht, das Element zu finden und darauf zu klicken. Wenn sich das DOM zwischen Suchen und Klicken ändert, wird es erneut versucht. Die Idee ist, dass der zweite Versuch erfolgreich sein wird, wenn es fehlschlägt und ich es sofort erneut versuche. Wenn die DOM-Änderungen sehr schnell sind, funktioniert dies nicht.
public boolean retryingFindClick(By by) { boolean result = false; int attempts = 0; while(attempts < 2) { try { driver.findElement(by).click(); result = true; break; } catch(StaleElementException e) { } attempts++; } return result; }
quelle
Diese Fehler haben zwei häufige Ursachen: Das Element wurde vollständig gelöscht oder das Element ist nicht mehr mit dem DOM verbunden.
Wenn Sie bereits überprüft haben, ob dies nicht Ihr Fall ist, haben Sie möglicherweise das gleiche Problem wie ich.
Das Element im DOM wird nicht gefunden, da Ihre Seite nicht vollständig geladen ist, wenn Selenium nach dem Element sucht. Um dies zu lösen, können Sie eine explizite Wartebedingung festlegen, die Selenium anweist, zu warten, bis das Element zum Klicken verfügbar ist.
from selenium.webdriver.support import expected_conditions as EC wait = WebDriverWait(driver, 10) element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))
Siehe: https://selenium-python.readthedocs.io/waits.html
quelle
Die Sache hier ist, dass Sie eine for-Schleife außerhalb Ihrer bedingten Anweisung verwenden.
Nachdem die Bedingungen in Ihrer IF-Anweisung erfüllt sind, navigieren Sie wahrscheinlich zu einer anderen Seite. Wenn die for-Schleife erneut versucht zu iterieren, wird der Fehler "Veraltetes Element" angezeigt, da Sie sich auf einer anderen Seite befinden.
Sie können am Ende Ihrer if-Anweisung eine Pause einfügen, dies hat bei mir funktioniert.
quelle
Brechen Sie einfach die Schleife, wenn Sie das Element finden, auf das Sie klicken möchten. zum Beispiel:
List<WebElement> buttons = getButtonElements(); for (WebElement b : buttons) { if (b.getText().equals("Next"){ b.click(); break; }
quelle
Verwenden Sie diesen Code:
public class LinkTest { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.navigate().to("file:///C:/Users/vkiran/Desktop/xyz.html"); List<WebElement> alllinks =driver.findElements(By.xpath("//*[@id='sliding-navigation']//a")); String a[]=new String[alllinks.size()]; for(int i=0;i<alllinks.size();i++) { a[i]=alllinks.get(i).getText(); if(a[i].startsWith("B")) { System.out.println("clicking on this link::"+driver.findElement(By.linkText(a[i])).getText()); driver.findElement(By.linkText(a[i])).click(); } else { System.out.println("does not starts with B so not clicking"); } } } }
quelle
try { WebElement button = driver.findElement(By.xpath("xpath")); button.click(); } catch(org.openqa.selenium.StaleElementReferenceException ex) { WebElement button = driver.findElement(By.xpath("xpath")); button.click(); }
Dieser Try / Catch-Code hat tatsächlich bei mir funktioniert. Ich habe den gleichen veralteten Elementfehler.
quelle
Dies könnte in neueren Versionen von Selen in JS erfolgen (aber alle unterstützenden StalenessOf funktionieren):
const { until } = require('selenium-webdriver'); driver.wait( until.stalenessOf( driver.findElement( By.css(SQLQueriesByPhpMyAdminSelectors.sqlQueryArea) ) ), 5 * 1000 ) .then( driver.findElement(By.css(SQLQueriesByPhpMyAdminSelectors.sqlQueryArea)) .sendKeys(sqlString) );
quelle
Laut @Abhishek Singh müssen Sie das Problem verstehen:
und Sie können nicht mehr darauf verweisen (stellen Sie sich vor, welche ID des Elements sich geändert hat).
Folgen Sie dem Code:
class TogglingPage { @FindBy(...) private WebElement btnTurnOff; @FindBy(...) private WebElement btnTurnOn; TogglingPage turnOff() { this.btnTurnOff.isDisplayed(); this.btnTurnOff.click(); // when clicked, button should swap into btnTurnOn this.btnTurnOn.isDisplayed(); this.btnTurnOn.click(); // when clicked, button should swap into btnTurnOff this.btnTurnOff.isDisplayed(); // throws an exception return new TogglingPage(); } }
Fragen wir uns jetzt warum?
btnTurnOff
wurde von einem Fahrer gefunden - okbtnTurnOff
wurde ersetzt durchbtnTurnOn
- okbtnTurnOn
wurde von einem Fahrer gefunden. - OKbtnTurnOn
wurde ersetzt durchbtnTurnOff
- okthis.btnTurnOff.isDisplayed();
das Element auf, das im Selen-Sinne nicht mehr existiert - Sie können es sehen, es funktioniert perfekt, aber es ist eine andere Instanz derselben Schaltfläche .Mögliche Lösung:
TogglingPage turnOff() { this.btnTurnOff.isDisplayed(); this.btnTurnOff.click(); TogglingPage newPage = new TogglingPage(); newPage.btnTurnOn.isDisplayed(); newPage.btnTurnOn.click(); TogglingPage newerPage = new TogglingPage(); newerPage.btnTurnOff.isDisplayed(); // ok return newerPage; }
quelle
In meinem Fall hatte ich eine Seite, auf der es sich um eine Seite handelte,
input type='date'
deren Referenz ich beim Laden der Seite erhalten hatte, aber als ich versuchte, damit zu interagieren, zeigte diesexception
und das ziemlich aussagekräftig, daJavascript
meine Steuerung manipuliert worden war und sie daher vom Dokument getrennt wurde und ich musste aufre-get
seine Referenz verweisen, nachdem das Javascript seine Arbeit mit der Kontrolle ausgeführt hatte. So sah mein Code vor der Ausnahme aus:if (elemDate != null) { elemDate.Clear(); elemDate.SendKeys(model.Age); }
Code nach Auslösung der Ausnahme:
int tries = 0; do { try { tries++; if (elemDate != null) { // these lines were causing the exception so I had break after these are successfully executed because if they are executed that means the control was found and attached to the document and we have taken the reference of it again. elemDate.Clear(); elemDate.SendKeys(model.Age); break; } } catch (StaleElementReferenceException) { System.Threading.Thread.Sleep(10); // put minor fake delay so Javascript on page does its actions with controls elemDate = driver.FindElement(By.Id(dateId)); } } while (tries < 3); // Try it three times.
Jetzt können Sie weitere Aktionen mit Ihrem Code ausführen oder den Treiber beenden, wenn die Steuerung nicht funktioniert.
if(tries > 2) { // element was not found, find out what is causing the control detachment. // driver.Quit(); return; } // Hurray!! Control was attached and actions were performed. // Do something with it...
PS: Nachdem ich das alles geschrieben hatte, bemerkte ich nur die Tags, für die dieser Thread war
java
. Dieses Codebeispiel dient nur zu Demonstrationszwecken. Es kann Personen helfen, die Probleme mit derC#
Sprache haben. Oder es kann leicht übersetzt werden,java
da es nicht vielC#
spezifischen Code hat.quelle
Verwenden Sie diesen Code, um zu warten, bis das Element angehängt ist:
boolean breakIt = true; while (true) { breakIt = true; try { // write your code here } catch (Exception e) { if (e.getMessage().contains("element is not attached")) { breakIt = false; } } if (breakIt) { break; } }
quelle