Tôi đang triển khai rất nhiều bài kiểm tra Selenium bằng Java. Đôi khi, các thử nghiệm của tôi không thành công do một số StaleElementReferenceException
. Bạn có thể đề xuất một số cách tiếp cận để làm cho các bài kiểm tra ổn định hơn?Làm thế nào để tránh "StaleElementReferenceException" trong Selenium?
Trả lời
Điều này có thể xảy ra nếu hoạt động DOM xảy ra trên trang tạm thời khiến cho yếu tố không thể truy cập được. Để cho phép những trường hợp đó, bạn có thể thử truy cập phần tử vài lần trong một vòng lặp trước khi cuối cùng ném một ngoại lệ.
Hãy thử this excellent solution from darrelgrainger.blogspot.com:
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;
}
Nói chung điều này là do DOM được cập nhật và bạn cố gắng truy cập vào một/yếu tố mới được cập nhật - nhưng của sảng khoái vì vậy nó là một tham chiếu không hợp lệ bạn có ..
DOMLàm quen với điều này bằng cách sử dụng phần tử chờ đợi rõ ràng trên phần tử để đảm bảo cập nhật hoàn tất, sau đó lấy lại tham chiếu mới cho phần tử.
Dưới đây là một số mã giả để minh họa (Phỏng theo một số mã C# tôi sử dụng cho CHÍNH XÁC vấn đề này):
WebDriverWait wait = new WebDriverWait(browser, TimeSpan.FromSeconds(10));
IWebElement aRow = browser.FindElement(By.XPath(SOME XPATH HERE);
IWebElement editLink = aRow.FindElement(By.LinkText("Edit"));
//this Click causes an AJAX call
editLink.Click();
//must first wait for the call to complete
wait.Until(ExpectedConditions.ElementExists(By.XPath(SOME XPATH HERE));
//you've lost the reference to the row; you must grab it again.
aRow = browser.FindElement(By.XPath(SOME XPATH HERE);
//now proceed with asserts or other actions.
Hope this helps!
Tôi gặp sự cố này không liên tục. Không biết với tôi, BackboneJS đang chạy trên trang và thay thế phần tử mà tôi đang cố gắng nhấp vào. Mã của tôi trông như thế này.
driver.findElement(By.id("checkoutLink")).click();
Tất nhiên là có chức năng giống như thế này.
WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
checkoutLink.click();
Điều gì sẽ xảy ra thường xuyên là javascript sẽ thay thế phần tử checkoutLink giữa tìm và nhấp vào nó, tức là.
WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
// javascript replaces checkoutLink
checkoutLink.click();
Điều gì đã dẫn đến StaleElementReferenceException đúng khi cố gắng nhấp vào liên kết. Tôi không thể tìm thấy bất kỳ cách đáng tin cậy để nói với WebDriver để chờ cho đến khi javascript đã chạy xong, vì vậy đây là cách cuối cùng tôi đã giải quyết nó.
new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until(new Predicate<WebDriver>() {
@Override
public boolean apply(@Nullable WebDriver driver) {
driver.findElement(By.id("checkoutLink")).click();
return true;
}
});
Mã này sẽ liên tục cố nhấp vào liên kết, bỏ qua StaleElementReferenceChú ý cho đến khi nhấp chuột thành công hoặc hết thời gian chờ. Tôi thích giải pháp này vì nó tiết kiệm cho bạn phải viết bất kỳ logic thử lại nào và chỉ sử dụng các cấu trúc dựng sẵn của WebDriver.
Có thể nó đã được thêm gần đây, nhưng các câu trả lời khác không đề cập đến tính năng chờ ngầm của Selenium, tất cả những điều trên đều dành cho bạn và được tích hợp vào Selenium.
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
này sẽ thử lại findElement()
cuộc gọi cho đến khi nguyên tố này đã được tìm thấy, hoặc trong 10 giây.
Nguồn - http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp
Giải pháp đó không ngăn StaleElementReferenceException – MrSpock
Chỉ để loại bỏ bất kỳ sự nhầm lẫn nào trên các phiên bản, ngay cả trong phiên bản mới nhất của Selenium implicitlyWait() KHÔNG ngăn chặn StaleElementReferenceException. Tôi sử dụng một phương thức gọi trong vòng lặp với giấc ngủ, cho đến khi thành công hoặc số cố định. –
Một giải pháp trong C# sẽ là:
Helper lớp:
internal class DriverHelper
{
private IWebDriver Driver { get; set; }
private WebDriverWait Wait { get; set; }
public DriverHelper(string driverUrl, int timeoutInSeconds)
{
Driver = new ChromeDriver();
Driver.Url = driverUrl;
Wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeoutInSeconds));
}
internal bool ClickElement(string cssSelector)
{
//Find the element
IWebElement element = Wait.Until(d=>ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver);
return Wait.Until(c => ClickElement(element, cssSelector));
}
private bool ClickElement(IWebElement element, string cssSelector)
{
try
{
//Check if element is still included in the dom
//If the element has changed a the OpenQA.Selenium.StaleElementReferenceException is thrown.
bool isDisplayed = element.Displayed;
element.Click();
return true;
}
catch (StaleElementReferenceException)
{
//wait until the element is visible again
element = Wait.Until(d => ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver);
return ClickElement(element, cssSelector);
}
catch (Exception)
{
return false;
}
}
}
Invocation:
DriverHelper driverHelper = new DriverHelper("http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp", 10);
driverHelper.ClickElement("input[value='csharp']:first-child");
Tương tự như vậy có thể được sử dụng cho Java.
Lý do tại sao xảy ra StaleElementReferenceException
đã được đưa ra: cập nhật cho DOM giữa việc tìm kiếm và thực hiện điều gì đó với phần tử.
Đối với nhấp Vấn đề tôi đã sử dụng gần đây một giải pháp như thế này:
public void clickOn(By locator, WebDriver driver, int timeout)
{
final WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(ExpectedConditions.refreshed(
ExpectedConditions.elementToBeClickable(locator)));
driver.findElement(locator).click();
}
Các phần quan trọng là "chain" của của Selenium riêng ExpectedConditions
qua ExpectedConditions.refreshed()
. Điều này thực sự chờ đợi và kiểm tra xem phần tử được đề cập đã được làm mới trong thời gian chờ đã chỉ định hay chưa và chờ đợi cho phần tử trở thành có thể nhấp.
Hãy xem qua số documentation for the refreshed method.
giải pháp Kenny là tốt, tuy nhiên nó có thể được viết theo một cách thanh lịch hơn
new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until((WebDriver d) -> {
d.findElement(By.id("checkoutLink")).click();
return true;
});
Hoặc thêm:
new WebDriverWait(driver, timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.id("checkoutLink")));
driver.findElement(By.id("checkoutLink")).click();
Trong dự án của tôi, tôi đã giới thiệu một khái niệm StableWebElement. Nó là một wrapper cho WebElement mà có thể phát hiện nếu phần tử là cũ và tìm một tham chiếu mới cho phần tử gốc. Tôi đã thêm một phương thức trợ giúp để định vị các phần tử trả về StableWebElement thay vì WebElement và vấn đề với StaleElementReference đã biến mất.
public static IStableWebElement FindStableElement(this ISearchContext context, By by)
{
var element = context.FindElement(by);
return new StableWebElement(context, element, by, SearchApproachType.First);
}
Mã trong C# có sẵn trên trang của dự án của tôi, nhưng nó có thể dễ dàng chuyển sang java https://github.com/cezarypiatek/Tellurium/blob/master/Src/MvcPages/SeleniumUtils/StableWebElement.cs
này làm việc cho tôi (100% lao động) sử dụng C#
public Boolean RetryingFindClick(IWebElement webElement)
{
Boolean result = false;
int attempts = 0;
while (attempts < 2)
{
try
{
webElement.Click();
result = true;
break;
}
catch (StaleElementReferenceException e)
{
Logging.Text(e.Message);
}
attempts++;
}
return result;
}
- 1. Làm thế nào để sử dụng JQuery trong Selenium?
- 2. Làm thế nào để tránh nói "gstring"?
- 3. Làm thế nào để tránh downcast?
- 4. Làm thế nào để thay đổi selenium user agent trong selenium-webdriver nodejs land?
- 5. Làm thế nào để tránh deadlocks?
- 6. Làm thế nào để tránh lặp lại trong MSBuild?
- 7. Làm thế nào để tránh mất macro trong PHPExcel?
- 8. Làm thế nào để tránh thoát kép trong chuỗi C#?
- 9. Làm thế nào để tránh tìm kiếm vector trong data.table
- 10. Làm thế nào để tránh một stacktrace dài trong rspec
- 11. Làm thế nào để tránh macro ẩn trong Clojure?
- 12. Làm thế nào để tránh một postback trong JavaScript?
- 13. Làm thế nào để tránh tràn ngăn xếp trong Haskell?
- 14. Làm thế nào để tránh con trỏ null trong View.getDrawingCache()?
- 15. Làm thế nào để sử dụng Selenium với PHP?
- 16. Làm thế nào để gỡ lỗi Selenium WebDriver hành động?
- 17. Làm thế nào để tắt Javascript khi sử dụng Selenium?
- 18. Làm thế nào để tránh ngoại lệ stackoverflow này?
- 19. Xoắn luồng làm thế nào để tránh deepcopy
- 20. Làm thế nào để tránh tràn số nguyên?
- 21. Observable.Timer(): Làm thế nào để tránh trôi hẹn giờ?
- 22. Làm thế nào để tránh không xác định bù đắp
- 23. Làm thế nào để tránh nhiều nếu kiểm tra vô
- 24. Làm thế nào để tránh OutOfMemoryException khi chạy Hadoop?
- 25. Làm thế nào để tránh các tham số?
- 26. Làm thế nào để tránh các biến toàn cầu
- 27. Làm thế nào để tránh LinearAlloc Vượt lỗi Dung android
- 28. Làm thế nào để tránh trọng số lồng nhau?
- 29. Selenium-rc: Làm thế nào để bạn sử dụng CaptureNetworkTraffic trong python
- 30. Làm thế nào để bấm một yếu tố trong Selenium WebDriver sử dụng JavaScript
Wow! Đây chỉ là những gì tôi cần. Cảm ơn! – SpartaSixZero
Nó cũng có thể được sửa bằng cách sử dụng tham chiếu khác nhau của phần tử. –
Điều đó trong khi với 2 retries là một giải pháp rất bẩn, chờ đợi nên được ưa thích. Xem giải pháp của tôi – cocorossello