Вопрос-ответ

How to avoid "StaleElementReferenceException" in Selenium?

Как избежать "StaleElementReferenceException" в Selenium?

Я реализую множество тестов Selenium с использованием Java - иногда мои тесты завершаются неудачей из-за StaleElementReferenceException.

Не могли бы вы предложить несколько подходов к повышению стабильности тестов?

Переведено автоматически
Ответ 1

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

Попробуйте это отличное решение от 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;
}
Ответ 2

У меня периодически возникала эта проблема. Без моего ведома BackboneJS запускался на странице и заменял элемент, на который я пытался щелкнуть. Мой код выглядел следующим образом.

driver.findElement(By.id("checkoutLink")).click();

Который, конечно, функционально такой же, как этот.

WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
checkoutLink.click();

Иногда случалось, что javascript заменял элемент checkoutLink между поиском и щелчком по нему, т.е.

WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
// javascript replaces checkoutLink
checkoutLink.click();

Что справедливо привело к StaleElementReferenceException при попытке перейти по ссылке. Я не смог найти никакого надежного способа сообщить webdriverу подождать, пока javascript не завершит работу, поэтому вот как я в конечном итоге решил это.

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

Этот код будет постоянно пытаться щелкнуть ссылку, игнорируя StaleElementReferenceExceptions, пока щелчок не завершится успешно или не истечет время ожидания. Мне нравится это решение, потому что оно избавляет вас от необходимости писать какую-либо логику повторных попыток и использует только встроенные конструкции WebDriver.

Ответ 3

Решение Кенни хорошее, однако его можно написать более элегантным способом

new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until((WebDriver d) -> {
d.findElement(By.id("checkoutLink")).click();
return true;
});

Или также:

new WebDriverWait(driver, timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.id("checkoutLink")));
driver.findElement(By.id("checkoutLink")).click();

Но в любом случае, лучшее решение - полагаться на библиотеку Selenide, она обрабатывает такого рода вещи и многое другое. (вместо ссылок на элементы он обрабатывает прокси, поэтому вам никогда не придется иметь дело с устаревшими элементами, что может быть довольно сложно). Selenide

Ответ 4

Обычно это происходит из-за обновления DOM, и вы пытаетесь получить доступ к обновленному / новому элементу - но DOM обновлен, поэтому у вас недействительная ссылка..

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

Вот некоторый псевдокод для иллюстрации (адаптирован из некоторого кода C #, который я использую для ИМЕННО этой проблемы):

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.

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

java selenium-webdriver