it-swarm.com.de

veraltete Elementreferenz: Element ist nicht an das Seitendokument angehängt

Ich habe eine Liste mit mehreren Links unter jedem Abschnitt. Jeder Abschnitt hat die gleichen Links. Ich muss unter jedem Abschnitt auf einen bestimmten Link klicken. Ich habe den folgenden Code geschrieben, aber wenn er ausgeführt wird, gibt es 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 Fehlerspur ist: 

    Exception in thread "main" 
org.openqa.Selenium.StaleElementReferenceException: stale element 
reference: element is not attached to the page document
40
Patil Prashanth

Was ist die Linie, die eine Ausnahme gibt?

Der Grund dafür ist, dass das Element, auf das Sie sich bezogen haben, aus der DOM-Struktur entfernt wird

Bei der Arbeit mit IEDriver stand ich vor dem gleichen Problem. Der Grund dafür war, dass Javascript das Element noch einmal geladen hatte, nachdem ich darauf hingewiesen hatte. Daher verweist meine Datumsreferenz auf ein nicht vorhandenes Objekt, auch wenn es auf der Benutzeroberfläche richtig war. Ich habe die folgende Problemumgehung verwendet.

try {
    WebElement date = driver.findElement(By.linkText(Utility.getSheetData(path, 7, 1, 2)));
    date.click();
}
catch(org.openqa.Selenium.StaleElementReferenceException ex)
{
    WebElement date = driver.findElement(By.linkText(Utility.getSheetData(path, 7, 1, 2)));
    date.click();
}

Sehen Sie, ob das gleiche Ihnen helfen kann!

46
Abhishek Singh

Um damit umzugehen, verwende ich die folgende Klickmethode ..__, die versuchen wird, das Element zu finden und darauf zu klicken. Wenn das DOM zwischen Suchen und Klicken wechselt, wird es erneut versucht. Die Idee ist, dass der zweite Versuch erfolgreich ist, wenn er 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;
}
5
Alisha Raju

Wenn Sie mit diesem Problem konfrontiert werden, definieren Sie einfach das Webelement oberhalb der Zeile, in der der Fehler auftritt, Ex: -

WebElement button = driver.findElement(By.xpath("xpath"));

button.click();

// hier machst du so etwas wie update oder save 

// Sie verwenden erneut die Schaltfläche WebElement, um darauf zu klicken 

button.click();

Lösung: -

WebElement button = driver.findElement(By.xpath("xpath"));
button.click();

// hier machst du so etwas wie update oder save 

// Sie definieren erneut das Schaltflächenelement, bevor Sie es verwenden

WebElement button1 = driver.findElement(By.xpath("xpath"));
button1.click();

// so dass das neue Element auf dasselbe Element im neuen DOM verweist 

4
rohit goudar

Diese Fehler haben zwei häufige Ursachen: Das Element wurde vollständig gelöscht oder das Element ist nicht mehr an das DOM angehängt.

Wenn Sie bereits geprüft haben, ob es nicht Ihr Fall ist, könnten Sie das gleiche Problem wie ich haben.

Das Element im DOM wird nicht gefunden, da Ihre Seite nicht vollständig geladen wird, wenn Selenium nach dem Element sucht. Um dies zu lösen, können Sie eine explizite Wartebedingung setzen, die Selenium anweist, zu warten, bis das Element zum Anklicken 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

2
Bruno Sanches

Die Sache hier ist, dass Sie eine for-Schleife außerhalb Ihrer Bedingungsanweisung verwenden.

Nachdem die Bedingungen in Ihrer IF-Anweisung erfüllt sind, navigieren Sie wahrscheinlich zu einer anderen Seite. Wenn also die for-Schleife erneut zu iterieren versucht, wird der Fehler "veraltetes Element" angezeigt, da Sie sich auf einer anderen Seite befinden.

Sie können eine break am Ende Ihrer if-Anweisung hinzufügen, dies hat für mich funktioniert.

2
Adrian Coroi

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");
            }
        }
}
}
2
kiran

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;
        }
1
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 für mich funktioniert. Ich habe den gleichen Fehler des veralteten Elements erhalten.

1
Charan Raz

Laut @Abhishek Singh müssen Sie das Problem verstehen:

Was ist die Linie, die Ausnahme gibt? Der Grund dafür ist, dass das Element, auf das Sie sich bezogen haben, entfernt aus der DOM-Struktur ist

und Sie können nicht mehr darauf verweisen (stellen Sie sich vor, welche Element-ID 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?

  1. btnTurnOff wurde von einem Fahrer gefunden - ok
  2. btnTurnOff wurde durch btnTurnOn ersetzt - ok
  3. btnTurnOn wurde von einem Fahrer gefunden. - okay
  4. btnTurnOn wurde durch btnTurnOff ersetzt - ok
  5. wir rufen this.btnTurnOff.isDisplayed(); für das Element auf, das nicht mehr im Sinne von Selen existiert - Sie können es sehen, es funktioniert perfekt, aber es ist ein andere Instanz der gleichen 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;
  }
0
J.Wincewicz

Dies könnte in neueren Versionen von Selenium in JS durchgeführt werden (aber alle, die stalenessOf unterstützen, werden 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)
  );
0
SkorpEN

In meinem Fall hatte ich eine Seite, auf der es sich um ein input type='date', dessen Referenz ich beim Laden der Seite erhalten hatte, aber als ich versuchte, mit ihr zu interagieren, zeigte sie dieses exception und das war ziemlich bedeutungsvoll, da Javascript mein Steuerelement manipuliert hatte, weshalb es davon getrennt wurde das dokument und ich mussten re-get sein Verweis, nachdem das Javascript seine Arbeit mit dem Steuerelement ausgeführt hatte. So sah mein Code vor der Ausnahme aus:

if (elemDate != null)
{ 
    elemDate.Clear(); 
    elemDate.SendKeys(model.Age);
}

Code, nachdem die Ausnahme ausgelöst wurde:

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 es nicht gelungen ist, das Steuerelement zum Laufen zu bringen.

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...

Was ich bisher gelernt habe, ist, dass es keine gute Idee ist, Ausnahmen zu treffen, um über eine erfolgreiche Codeausführung Bescheid zu wissen. Aber ich musste es tun und fand das work-around in diesem Fall gut funktionieren.

PS: Nachdem ich das alles geschrieben habe, habe ich gerade die Tags bemerkt, die dieser Thread für Java war. Dieses Codebeispiel dient nur zu Demonstrationszwecken. Es kann Menschen mit Problemen in C# Sprache. Oder es kann leicht in Java übersetzt werden, da es nicht viel C# spezifischer Code.

0
Jamshaid Kamran