verouderde elementreferentie: element is niet gekoppeld aan het paginadocument

Ik heb een lijst met meerdere links onder elke sectie. Elke sectie heeft dezelfde links. Ik moet onder elke sectie op een bepaalde link klikken. Ik heb de onderstaande code geschreven, maar wanneer deze wordt uitgevoerd, krijg ik de fout stale element reference: element is not attached to the page document.

Dit is mijn 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++;
    }
}
}

Dit is de HTML-structuur zoals hieronder

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

Het fouttraceer is:

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

Antwoord 1, Autoriteit 100%

Wat is de lijn die uitzondering geeft ??

De reden hiervoor is omdat het element waarnaar u heeft verwezen, uit de DOM-structuur is verwijderd

Ik had hetzelfde probleem toen ik met IEDriver werkte. De reden was dat javascript het element nog een keer laadde nadat ik heb verwezen, dus mijn datumreferentie wees naar een niet-bestaand object, zelfs als het daar in de gebruikersinterface stond. Ik heb de volgende oplossing gebruikt:

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();
}

Kijk of hetzelfde u kan helpen!


Antwoord 2, autoriteit 63%

Als u met dit probleem wordt geconfronteerd, definieert u het webelement nogmaalsboven de regel waarin u een foutmelding krijgt.

Voorbeeld:

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();

Sinds de DOM is gewijzigd, b.v. via de update-actie ontvangt u een StaleElementReference-fout.

Oplossing:

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();

Antwoord 3, autoriteit 14%

Deze fouten hebben twee veelvoorkomende oorzaken: het element is volledig verwijderd of het element is niet langer gekoppeld aan de DOM.

Als je al hebt gecontroleerd of dit niet jouw geval is, heb je mogelijk hetzelfde probleem als ik.

Het element in de DOM is niet gevonden omdat uw pagina niet volledig is geladen wanneer Selenium naar het element zoekt. Om dat op te lossen, kun je een expliciete wachtvoorwaarde instellen die Selenium vertelt te wachten tot het element beschikbaar is om op te klikken.

from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

Zie: https://selenium-python.readthedocs.io/waits.html

In Java

import org.openqa.selenium.support.ui.ExpectedConditions;
WebDriverWait wait = new WebDriverWait(driver, 10);
element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

Zie: https ://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html


Antwoord 4, autoriteit 8%

Om het af te handelen, gebruik ik de volgende klikmethode.
Hiermee wordt geprobeerd het element te vinden en erop te klikken. Als de DOM verandert tussen zoeken en klikken, wordt het opnieuw geprobeerd. Het idee is dat als het mislukt en ik het meteen weer probeer, de tweede poging wel zal lukken. Als de DOM-wijzigingen erg snel gaan, werkt dit niet.

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;
}

Antwoord 5, Autoriteit 4%

Het ding hier is dat u een voor lus gebruikt buiten uw voorwaardelijke verklaring.

Nadat de omstandigheden in uw als er een verklaring zijn voldaan, navigeren u waarschijnlijk naar een andere pagina, dus wanneer de lus probeert opnieuw te herhalen, krijgt u de fout van het muffelement, omdat u op een andere pagina staat.

U kunt een pauze toevoegen aan het einde van uw IF-verklaring, dit werkte voor mij.


Antwoord 6, Autoriteit 3%

Breek gewoon de lus wanneer u het element vindt dat u erop wilt klikken.
Bijvoorbeeld:

 List<WebElement> buttons = getButtonElements();
    for (WebElement b : buttons) {
        if (b.getText().equals("Next"){
            b.click();
            break;
        }

Antwoord 7, Autoriteit 2%

Gebruik deze 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");
            }
        }
}
}

Antwoord 8

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();
}

Deze try/catch-code werkte echt voor mij. Ik kreeg dezelfde fout met het verouderde element.


Antwoord 9

Dit zou kunnen worden gedaan in nieuwere versies van selenium in JS (maar alle ondersteunende stalenessOfzullen werken):

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)
  );

Antwoord 10

Volgens @Abhishek Singh’s moet je het probleem begrijpen:

Wat is de regel die uitzondering geeft ??
De reden hiervoor is dat het element waarnaar u verwijst, is verwijderduit de DOM-structuur

en je kunt er niet meer naar verwijzen (stel je voor welk element’s ID is veranderd).

Volg de 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();
  }
}

Laten we ons afvragen waarom?

  1. btnTurnOffis gevonden door een bestuurder – ok
  2. btnTurnOffis vervangen door btnTurnOn– ok
  3. btnTurnOnis gevonden door een bestuurder. – oke
  4. btnTurnOnis vervangen door btnTurnOff– ok
  5. we noemen this.btnTurnOff.isDisplayed();op het element dat niet meer bestaat in de zin van Selenium – je kunt het zien, het werkt perfect, maar het is een andere instantie van dezelfde knop.

Mogelijke oplossing:

 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;
  }

Antwoord 11

In mijn geval had ik een pagina waar het een input type='date'was waarvan ik de referentie had gekregen bij het laden van de pagina, maar toen ik probeerde ermee te werken, toonde het dit exceptionen dat was behoorlijk zinvol omdat Javascriptmijn controle had gemanipuleerd, daarom was het losgekoppeld van het document en moest ik de verwijzing re-getophalen na de javascript had zijn werk gedaan met de besturing.
Dus zo zag mijn code eruit vóór de uitzondering:

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

Code nadat de uitzondering is opgetreden:

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.

Dus u kunt nu verdere acties uitvoeren met uw code of u kunt het stuurprogramma afsluiten als het niet gelukt is om de besturing aan het werk te krijgen.

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

Iets dat ik tot nu toe heb geleerd, is dat je uitzonderingen moet weten
over succesvolle code-uitvoering is geen goed idee, maar ik moest het doen
en ik ontdekte dat deze work-aroundin dit geval goed werkte.

PS: Nadat ik dit allemaal had geschreven, zag ik net de tags dat deze thread voor javawas. Dit codevoorbeeld is alleen voor demonstratiedoeleinden, het kan mensen helpen die een probleem hebben in de taal C#. Of het kan eenvoudig worden vertaald naar javaomdat het niet veel C#-specifieke code heeft.


Antwoord 12

In mijn geval heeft de locator die ik gebruikte meerdere resultaten, dus het was niet in staat om het juiste element te identificeren om een actie uit te voeren, uiteindelijk werd er een uitzondering gegenereerd.
Dus het hebben van een unieke locator heeft mijn probleem opgelost.


Antwoord 13

gebruik deze code om te wachten tot het element is bijgevoegd:

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;
        }
    }

Other episodes