Ссылка на устаревший элемент: элемент не прикреплен к документу страницы

У меня есть список, который имеет несколько ссылок под каждым разделом. Каждый раздел имеет одинаковые ссылки, мне нужно нажать на конкретную ссылку под каждым разделом. Я написал код ниже, но когда он выполняется, он дает мне stale element reference: element is not attached to the page document ошибка.

Это мой код:

public static void main(String[] args) throws InterruptedException 
{
    WebDriver driver = new ChromeDriver();
    driver.navigate().to("url......");
        driver.findElement(By.id("Login1_txtEmailID")).sendKeys("hourbank5@....com");
    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++;
    }
}

}

Это структура HTML, как показано ниже

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

Трассировка ошибок:

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

16 ответов

Какая линия дает исключение??

Причина этого в том, что элемент, на который вы ссылались, удаляется из структуры DOM

Я столкнулся с той же проблемой при работе с IEDriver. Причина была в том, что javascript загрузил элемент еще раз после того, как я сослался на него, поэтому моя ссылка на дату указала на несуществующий объект, даже если он был прав в их пользовательском интерфейсе. Я использовал следующий обходной путь.

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

Посмотрите, может ли то же самое помочь вам!

Всякий раз, когда вы сталкиваетесь с этой проблемой, просто определите веб-элемент еще раз над строкой, в которой появляется ошибка, например:

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

button.click();

// здесь вы делаете что-то вроде обновления или сохранения

// снова вы используете кнопку WebElement для нажатия

button.click();

Решение:-

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

// здесь вы делаете что-то вроде обновления или сохранения

// снова вы определяете элемент кнопки перед использованием

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

// чтобы новый элемент указывал на тот же элемент в новом DOM

Эти ошибки имеют две общие причины: элемент был полностью удален или элемент больше не присоединен к DOM.

Если вы уже проверили, если это не ваш случай, вы можете столкнуться с той же проблемой, что и я.

Элемент в DOM не найден, потому что ваша страница загружена не полностью, когда Selenium ищет этот элемент. Чтобы решить эту проблему, вы можете поставить явное условие ожидания, при котором Selenium будет ждать, пока не станет доступен элемент, по которому можно щелкнуть.

from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

Смотрите: https://selenium-python.readthedocs.io/waits.html

Чтобы справиться с этим, я использую следующий метод щелчка. Это попытается найти и щелкнуть элемент. Если DOM изменится между поиском и щелчком, он попытается снова. Идея состоит в том, что если это не удастся, и я попробую снова сразу же, вторая попытка будет успешной. Если изменения DOM очень быстрые, это не сработает.

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

Просто разорвите цикл, когда вы найдете элемент, который хотите щелкнуть по нему. например:

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

Дело в том, что вы используете цикл for вне вашего условного оператора.

После выполнения условий в вашем операторе IF вы, вероятно, переходите на другую страницу, поэтому, когда цикл for пытается выполнить итерацию еще раз, вы получаете ошибку устаревшего элемента, потому что вы находитесь на другой странице.

Вы можете добавить перерыв в конце вашего заявления if, это сработало для меня.

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

Этот код try/catch действительно работает для меня. Я получил ту же ошибку устаревшего элемента.

Используйте этот код:

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

Это может быть сделано в более новых версиях селена в JS(но все поддерживающие stalenessOf будут работать):

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

У меня была эта проблема несколько раз. В одном из моих случаев принятый ответ не решил мою проблему, так как для меня проблема заключалась в том, что центр элемента не был кликабельным, а выброшенное исключение вводит в заблуждение «устаревшая ссылка на элемент: элемент не прикреплен к документу страницы».

Для меня исправление заключалось в том, чтобы прокрутить до элемента, чтобы убедиться, что центр элемента можно щелкнуть.

Для этого я использовал следующий код:

      WebElement yourElement=
                driver.findElement(By.id("yourElementId"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", yourElement);
yourElement.click();

Надеюсь это поможет!

Согласно @Abhishek Singh's, вам нужно понять проблему:

Какая линия дает исключение?? Причина этого в том, что элемент, на который вы ссылались, удаляется из структуры DOM

и вы больше не можете ссылаться на него (представьте, какой идентификатор элемента изменился).

Следуйте коду:

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

Теперь давайте зададимся вопросом, почему?

  1. btnTurnOff был найден водителем - хорошо
  2. btnTurnOff был заменен btnTurnOn - Хорошо
  3. btnTurnOn был найден водителем. - Хорошо
  4. btnTurnOn был заменен btnTurnOff - Хорошо
  5. мы называем this.btnTurnOff.isDisplayed(); на элементе, который больше не существует в смысле Selenium - вы можете видеть это, он отлично работает, но это другой экземпляр той же кнопки.

Возможное исправление:

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

В моем случае у меня была страница, где это было input type='date' чья ссылка у меня была при загрузке страницы, но когда я пытался с ней взаимодействовать, это показывало exception и это было довольно значимым, как Javascript манипулировал моим контролем, поэтому он был отделен от документа, и мне пришлось re-get его ссылка после того, как JavaScript выполнил свою работу с контролем. Итак, вот как мой код выглядел перед исключением:

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

Код после исключения был поднят:

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.

Итак, теперь вы можете выполнять дальнейшие действия с вашим кодом или выходить из драйвера, если он не смог заставить работать элемент управления.

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

Кое-что из того, что я узнал, заключается в том, что перехват исключений для успешного выполнения кода не очень хорошая идея, но мне пришлось это сделать, и я нашел это work-around чтобы хорошо работать в этом случае.

PS: после написания всего этого я просто заметил теги, для которых эта тема java, Этот пример кода только для демонстрации, он может помочь людям, которые имеют проблемы в C# язык. Или это может быть легко переведено на java так как мало C# конкретный код.

В моем случае локатор, который я использовал, дал несколько результатов, поэтому он не смог идентифицировать правильный элемент для выполнения действия, в результате чего возникло исключение. Таким образом, наличие уникального локатора решило мою проблему.

В моем случае проблему решил просто ОФИЦИАНТ!

       public void ClickOnButton()
 {
        Driver.WaitForPageUntilIWebElementIsClickable(Button);
        Button.Click();
 }

Эта ошибка возникает при динамическом изменении css. xpath отлично работает на динамических веб-сайтах, или вы можете использовать веб-драйвер refresh().

Используйте этот код, чтобы дождаться присоединения элемента:

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

    }
Другие вопросы по тегам