referensi elemen basi: elemen tidak dilampirkan ke dokumen halaman


97

Saya memiliki daftar yang memiliki banyak tautan di bawah setiap bagian. Setiap bagian memiliki tautan yang sama. Saya perlu mengklik tautan tertentu di bawah setiap bagian. Saya telah menulis kode di bawah ini tetapi ketika dijalankan itu memberi saya stale element reference: element is not attached to the page documentkesalahan.

Ini kode saya:

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

}

Ini adalah struktur HTML seperti di bawah ini

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

Jejak Kesalahan adalah:

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

Jawaban:


81

Apa baris yang memberikan pengecualian ??

Alasannya adalah karena elemen yang Anda rujuk dihapus dari struktur DOM

Saya menghadapi masalah yang sama saat bekerja dengan IEDriver. Alasannya adalah karena javascript memuat elemen sekali lagi setelah saya merujuk sehingga referensi tanggal saya menunjuk ke objek yang tidak ada bahkan jika itu benar di UI mereka. Saya menggunakan solusi berikut.

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

Lihat apakah hal yang sama dapat membantu Anda!


linkTexts [i] = e.getText (); baris memberi saya kesalahan saat mengulang untuk kedua kalinya
Patil Prashanth

1
Mengatasi kesalahan itu karena penyegaran halaman 1. pertama saya menyalin semua teks tautan ke variabel array String dan kemudian digunakan untuk loop untuk mengklik tautan yang diperlukan di bawah setiap bagian. untuk (WebElement e: LeftNavLinks) {linkTexts [i] = e.getText (); i ++; } untuk (int j = 0; j <leftnavlen; j ++) {if (linkTexts [j] .equals (ben)) {String BenefitStatLi = "// * [@ id = 'sliding-navigation'] / li [% s ]/Sebuah"; driver.findElement (By.xpath (String.format (BenefitStatLi, j + 1))). click (); driver.findElement (By.xpath ("// * @ id = 'divContentHolder'] / div [1] / a [1]")). click (); }
Patil Prashanth

Jadi itu untuk alasan yang sama. Elemen yang diidentifikasi sebelumnya telah dihapus dari DOM karena penyegaran halaman :)
Abhishek Singh

Ya memang benar. Terima kasih banyak @AbhishekSingh
Rahal Kanishka

Dalam kasus saya, saya mendapat pengecualian ini karena saya tidak memiliki pernyataan istirahat di loop setelah elemen yang diperlukan diklik. Jadi hati-hati untuk situasi seperti itu juga.
Raj Asapu

48

Setiap kali Anda menghadapi masalah ini, cukup tentukan elemen web sekali lagi di atas garis di mana Anda mendapatkan Kesalahan.

Contoh:

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

Karena DOM telah berubah misalnya melalui tindakan pembaruan, Anda menerima StaleElementReferencekesalahan.

Larutan:

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


Hei, sepertinya ini telah menyelesaikan kesalahanku. Tetapi saya tidak mengerti mengapa saya harus mendefinisikan elemen yang sama seperti yang didefinisikan sebelumnya.
Abhi

8

Untuk mengatasinya, saya menggunakan metode klik berikut. Ini akan mencoba menemukan dan mengklik elemen tersebut. Jika DOM berubah antara temukan dan klik, DOM akan mencoba lagi. Idenya adalah jika gagal dan saya segera mencoba lagi, upaya kedua akan berhasil. Jika perubahan DOM sangat cepat maka ini tidak akan berhasil.

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

8

Kesalahan ini memiliki dua penyebab umum: Elemen telah dihapus seluruhnya, atau elemen tidak lagi dilampirkan ke DOM.

Jika Anda sudah memeriksa apakah itu bukan kasus Anda, Anda mungkin menghadapi masalah yang sama dengan saya.

Elemen di DOM tidak ditemukan karena halaman Anda tidak sepenuhnya dimuat saat Selenium mencari elemen tersebut. Untuk mengatasinya, Anda dapat menempatkan kondisi tunggu eksplisit yang memberi tahu Selenium untuk menunggu hingga elemen tersedia untuk diklik.

from selenium.webdriver.support import expected_conditions as EC

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

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


ini berhasil untuk saya. Juga tautan ke dokumen itu membantu dalam memahami cara kerjanya. Terima kasih @Bruno_Sanches
Nikunj Kakadiya

4

Masalahnya di sini adalah Anda menggunakan for loop di luar pernyataan kondisional Anda.

Setelah kondisi dalam pernyataan IF Anda terpenuhi, Anda mungkin menavigasi ke halaman lain, jadi saat loop for mencoba mengulang sekali lagi, Anda mendapatkan error elemen basi karena Anda berada di halaman yang berbeda.

Anda dapat menambahkan jeda di akhir pernyataan if Anda, ini berhasil untuk saya.


Butuh beberapa saat bagi saya untuk memahami mengapa kesalahan terjadi!
BEWARB

3

Putuskan saja loop ketika Anda menemukan elemen yang ingin Anda klik. sebagai contoh:

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

2

Gunakan kode ini:

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

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

Kode coba / tangkap ini benar-benar berfungsi untuk saya. Saya mendapat kesalahan elemen basi yang sama.


1
Apakah jawaban ini berbeda dari jawaban pilihan teratas di sini?
SiKing

1

Ini dapat dilakukan di versi selenium yang lebih baru di JS (tetapi semua stalenessOf pendukung akan berfungsi):

 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

Menurut @Abhishek Singh, Anda perlu memahami masalahnya:

Apa baris yang memberikan pengecualian ?? Alasannya adalah karena elemen yang Anda rujuk dihapus dari struktur DOM

dan Anda tidak dapat merujuknya lagi (bayangkan ID elemen apa yang telah berubah).

Ikuti kodenya:

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

Sekarang, mari kita bertanya-tanya mengapa?

  1. btnTurnOff ditemukan oleh sopir - ok
  2. btnTurnOffdiganti dengan btnTurnOn- ok
  3. btnTurnOnditemukan oleh seorang pengemudi. - baik
  4. btnTurnOndiganti dengan btnTurnOff- ok
  5. kami memanggil this.btnTurnOff.isDisplayed();elemen yang tidak ada lagi dalam pengertian Selenium - Anda dapat melihatnya, ini berfungsi dengan sempurna, tetapi ini adalah contoh berbeda dari tombol yang sama .

Perbaikan yang mungkin:

  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

Dalam kasus saya, saya memiliki halaman di mana itu adalah input type='date'referensi yang saya dapatkan pada pemuatan halaman, tetapi ketika saya mencoba berinteraksi dengannya, itu menunjukkan ini exceptiondan itu cukup berarti karena Javascripttelah memanipulasi kendali saya sehingga terlepas dari dokumen dan saya harus re-getmerujuknya setelah javascript melakukan tugasnya dengan kontrol. Jadi, beginilah tampilan kode saya sebelum pengecualian:

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

Kode setelah pengecualian dimunculkan:

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.

Jadi, Sekarang Anda dapat melakukan tindakan lebih lanjut dengan kode Anda atau Anda dapat keluar dari driver jika tidak berhasil mendapatkan kontrol untuk bekerja.

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

Sesuatu yang telah saya pelajari sejauh ini adalah, menangkap pengecualian untuk mengetahui tentang eksekusi kode yang sukses bukanlah ide yang baik, Tapi, saya harus melakukannya dan saya menemukan ini work-aroundberfungsi dengan baik dalam kasus ini.

PS: Setelah menulis semua ini, saya baru melihat tag untuk utas ini java. Contoh kode ini hanya untuk tujuan demonstrasi, Ini mungkin membantu orang-orang yang memiliki masalah dalam C#bahasa. Atau dapat dengan mudah diterjemahkan javakarena tidak memiliki banyak C#kode khusus.


-7

gunakan kode ini untuk menunggu sampai elemen dilampirkan:

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

    }

1
tidak berhasil untuk saya tetapi masih merupakan pendekatan yang menarik
Yar

28
Ini tidak masuk akal.
Sam

1
Masuk akal, hanya saja ini bukan yang paling jelas dalam istilah nama variabel "breakIt". Apa yang dilakukannya adalah keluar dari perulangan while (true) segera setelah kesalahan "elemen tidak dilampirkan" tidak lagi ditampilkan.
ampelas

'boolean doIt = true; while (doIt) {coba {// tulis kode Anda di sini} catch (Exception e) {if (e.getMessage (). contains ("element is not attach")) {doIt = false; }}} '
Tao Zhang

1
baunya seperti semangat pergi
Eugene Baranovsky
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.