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 document
kesalahan.
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("[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++;
}
}
}
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
sumber
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
StaleElementReference
kesalahan.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();
sumber
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; }
sumber
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
sumber
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.
sumber
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; }
sumber
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"); } } } }
sumber
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.
sumber
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) );
sumber
Menurut @Abhishek Singh, Anda perlu memahami masalahnya:
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?
btnTurnOff
ditemukan oleh sopir - okbtnTurnOff
diganti denganbtnTurnOn
- okbtnTurnOn
ditemukan oleh seorang pengemudi. - baikbtnTurnOn
diganti denganbtnTurnOff
- okthis.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; }
sumber
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 iniexception
dan itu cukup berarti karenaJavascript
telah memanipulasi kendali saya sehingga terlepas dari dokumen dan saya harusre-get
merujuknya 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...
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 dalamC#
bahasa. Atau dapat dengan mudah diterjemahkanjava
karena tidak memiliki banyakC#
kode khusus.sumber
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; } }
sumber