Selenium WebDriver StaleElementReferenceException
Я получаю эту ошибку при выполнении моих тестов:
org.openqa.selenium.StaleElementReferenceException: Элемент больше не привязан к DOM
любая идея о том, как решить вышеупомянутое исключение?
это происходит в моей сетке
который имеет выражение Xpath ref, которое является динамическим
Ответы
Ответ 1
Я столкнулся с этой же проблемой и не смог найти никаких решений. Придумал решение и разместил его здесь, надеясь, что это поможет кому-то с той же проблемой. Я создал класс для обработки устаревших элементов в зависимости от их типа, cssselector, id и т.д. И просто вызываю его, как если бы я был любым другим объектом страницы.
public void StaleElementHandleByID (String elementID){
int count = 0;
boolean clicked = false;
while (count < 4 || !clicked){
try {
WebElement yourSlipperyElement= driver.findElement(By.id(elementID));
yourSlipperyElement.click();
clicked = true;
} catch (StaleElementReferenceException e){
e.toString();
System.out.println("Trying to recover from a stale element :" + e.getMessage());
count = count+1;
}
}
Я бы рекомендовал использовать это только на тех элементах, которые, как вы знаете, вызывают проблемы для WebDriver.
Ответ 2
Мы обошли эту проблему, выполнив что-то, называемое WebdriverWrapper и WebElementWrapper.
Что делают эти обертки, обрабатывает StaleElementException внутри, а затем использует локатор для переоценки и получения нового объекта WebElement. Таким образом, вам необходимо распространить код, обрабатывающий исключение, по всей вашей кодовой базе и локализовать его в один класс.
Я скоро загляну в открытую подборку этих двух классов и добавлю ссылку здесь, если вас интересуют люди.
Ответ 3
Это исключение возникает при попытке использовать метод WebElement, который больше не находится на странице. Если ваша сетка динамически загружает данные и обновляет сетку, любые ссылки на элементы в этой сетке будут "устаревшими". Дважды проверьте, что элемент, который вы пытаетесь ссылаться, находится на странице в ваших тестах, и вам может потребоваться повторно создать объект.
Ответ 4
Он также столкнулся с этой проблемой. Похоже, что модальная загрузка панели падает в состояние гонки и продолжает ждать времени.
Я пробовал много раз и нашел, что решение состоит в том, чтобы удерживать загрузку модальной панели, пока он не может быть точно найден webDriver и в то же время обновить экземпляр webDriver, а затем попытаться найти WebElements внутри модальной панели.
Итак, решение выглядит следующим образом:
например MyModalPanel - это ваш идентификатор ModalPanel, затем выполните следующие действия
page.openModalPanel();
Assert.assertTrue(page.waitTillDisplay( "MyModalPanelContentDiv"), Wait.MODAL_PANEL));
page.fillInFormInModalpanel(formObj);
и код waitTillDisplay можно найти на веб-сайте WebDriver, я просто вставлю свой код здесь для справки:
public Boolean waitTillDisplay(final String id, int waitSeconds){
WebDriverWait wait = new WebDriverWait(driver, waitSeconds);
Boolean displayed = wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return driver.findElement(By.id(id)).isDisplayed();
}
});
return displayed;
}
Ответ 5
Возможно, вы попытаетесь получить какие-либо свойства элемента после нажатия элемента.
У меня была такая же проблема, я пытался нажать кнопку getText() после ее нажатия. В моем случае, как только кнопка нажата, появится новое окно.
Ответ 6
Я использовал FluentWait, а также ExpectedCondition применил переопределение: https://gist.github.com/djangofan/5112655. Это обрабатывает исключение внутри завершенного блока, в отличие от того, как другие люди отвечают на это, и позволяет последовательные попытки быть завернутыми в этот блок. Я думаю, что это более элегантно.
public static void clickByLocator( final By locator ) {
final long startTime = System.currentTimeMillis();
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(90000, TimeUnit.MILLISECONDS)
.pollingEvery(5500, TimeUnit.MILLISECONDS);
//.ignoring( StaleElementReferenceException.class );
wait.until( new ExpectedCondition<Boolean>() {
@Override
public Boolean apply( WebDriver webDriver ) {
try {
webDriver.findElement( locator ).click();
return true;
} catch ( StaleElementReferenceException e ) { // try again
return false;
}
}
} );
driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
log("Finished click after waiting for " + totalTime + " milliseconds.");
}
Ответ 7
Я сделал некоторые изменения более гибкими:
delegate void StaleFunction(IWebElement elt);
private static void StaleElementHandleByID(By by, StaleFunction func )
{
int count = 0;
while (count < 4)
{
try
{
IWebElement yourSlipperyElement = Driver.FindElement(by);
func(yourSlipperyElement);
count = count + 4;
}
catch (StaleElementReferenceException e)
{
count = count + 1;
}
}
}
StaleElementHandleByID(By.Id("identDdl"),
delegate(IWebElement elt)
{
SelectElement select = new SelectElement(elt);
select.SelectByText(tosave.ItemEquipamentoCem.CodigoCne.ToString());
});
Ответ 8
быстрое и грязное решение:
el.click()
time.sleep(1)
то продолжайте анализировать итерационным способом
Ответ 9
В этом случае тесты ищут элемент, который еще не загружен, или был обновлен. В результате исключение StaleElementException. Простое решение состоит в том, чтобы добавить fluentWait.
Ответ 10
public static Boolean executeElementSendKeys
(WebDriver driver, WebElement element, String sInputParameters) throws Exception {
return (Boolean) executeElementMaster
(driver, element, "sendKeys", sInputParameters, 30, true);
}
public static Boolean executeElementClear
(WebDriver driver, WebElement element) throws Exception {
return (Boolean) executeElementMaster (driver, element, "clear", "", 30, true);
}
public static String executeElementGetText
(WebDriver driver, WebElement element) throws Exception {
return (String) executeElementMaster (driver, element, "getText", "", 30, true);
}
public static Boolean executeElementClick
(WebDriver driver, WebElement element) throws Exception {
return (Boolean) executeElementMaster (driver, element, "click", "", 30, true);
}
public static boolean executeElementIsDisplayed
(WebDriver driver, WebElement element) throws Exception {
return (Boolean) executeElementMaster (driver, element, "isDisplayed", "", 30, true);
}
public static String executeElementGetAttribute
(WebDriver driver, WebElement element, String sInputParameters) throws Exception {
return (String) executeElementMaster
(driver, element, "getAttribute", sInputParameters, 30, true);
}
//Ниже приведен главный метод, который обрабатывает StaleElementReferenceException
и другие исключения.
//В разделе catch замените (Exception e)
на (StaleElementReferenceException e)
, если вы хотите, чтобы этот метод повторил действия (например, щелчок, sendkeys и т.д.) только для StaleElementReferenceException
, а не для других исключений.
private static Object executeElementMaster(WebDriver driver, WebElement element, String sExecuteAction, String sInputParametersOptional, int MaxTimeToWait,
boolean bExpectedElementState) throws Exception {
try {
// Local variable declaration
String sElementString = "";
String sElementXpath = "";
Object ReturnValue = "";
int Index = 0;
boolean bCurrentElementState = true;
boolean bWebDriverWaitUntilElementClickableFlag = false;
System.out.println("**** Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Expected : '" + bExpectedElementState + "'");
System.out.println("**** MaxTimeToWait ='" + MaxTimeToWait + "' seconds");
// Set browser timeout to 1 second. Will be reset to default later
driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
// Keep trying until 'MaxTimeToWait' is reached
for (int i = 0; i < MaxTimeToWait; i++) {
try {
// Get element xPath - and find element again
if (element != null && i < 2 && sElementString == "") {
sElementString = (element).toString();
if (sElementString.contains("xpath: ")) {
// Retrieve xPath from element, if available
Index = sElementString.indexOf("xpath: ");
sElementXpath = sElementString.substring(Index + 7, sElementString.length());
}
}
// Find Element again
if (sElementXpath != "" && i > 0) {
element = driver.findElement(By.xpath(sElementXpath));
}
// Execute the action requested
switch (sExecuteAction) {
case ("isDisplayed"):
// Check if element is displayed and save in bCurrentElementState variable
ReturnValue = element.isDisplayed();
bCurrentElementState = (Boolean) ReturnValue;
bWebDriverWaitUntilElementClickableFlag = true;
break;
case ("getText"):
ReturnValue = element.getText();
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
case ("sendKeys"):
// Scroll element into view before performing any action
element.sendKeys(sInputParametersOptional);
ReturnValue = true;
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
case ("clear"):
// Scroll element into view before performing any action
element.clear();
ReturnValue = true;
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
case ("click"):
// Scroll element into view before performing any action
element.click();
ReturnValue = true;
bCurrentElementState = true;
bWebDriverWaitUntilElementClickableFlag = false;
break;
default:
ReturnValue = element.getAttribute(sInputParametersOptional);
bCurrentElementState = true;
break;
}
} catch (Exception e) {
Thread.sleep(500);
bCurrentElementState = false;
ReturnValue = false;
}
if (bCurrentElementState == bExpectedElementState) {
// If element actual and expected states match, log result and return value
System.out.println("**** PASSED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' **** \n"
+ "Actual element status: '" + bCurrentElementState + "' Expected element status: '" + bExpectedElementState + "'");
break;
} else {
// If element actual and expected states do NOT match, loop until they match or timeout is reached
Thread.sleep(500);
}
}
// Reset browser timeout to default
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// Return value before exiting
if (bCurrentElementState != bExpectedElementState) {
// If element actual and expected states do NOT match, log result and return value
System.out.println("**** FAILED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' **** \n"
+ "Actual element status: '" + bCurrentElementState + "' Expected element status: '" + bExpectedElementState + "'");
if (sExecuteAction.equalsIgnoreCase("findElement")) {
ReturnValue = null;
}
}
return ReturnValue;
} catch (Exception e) {
System.out.println("Exception in executeElementMaster - " + e.getMessage());
throw (e);
}
}