Selenium WebDriver
Dostaję ten błąd podczas uruchamiania testów: org.openqa.selen.StaleElementReferenceException: Element nie jest już dołączony do DOM
Jakiś pomysł jak rozwiązać powyższy wyjątek? this happen in my grid który ma wyrażenie ref XPath, które jest dynamiczne
10 answers
Natknąłem się na ten sam problem i nie mogłem znaleźć żadnych rozwiązań. Wymyśliłem rozwiązanie i opublikowałem je tutaj, mam nadzieję, że pomoże to komuś z tym samym problemem. Stworzyłem klasę do obsługi starych elementów w zależności od ich typu, cssselector, id, itp. i po prostu wywołałem ją tak, jak każdy inny obiekt strony.
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;
}
}
Zalecałbym używanie tego tylko na elementach, które powodują problemy dla Webdrivera.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-06 11:50:13
Możemy obejść ten problem, robiąc coś o nazwie WebdriverWrapper i WebElementWrapper.
Owijarki obsługują StaleElementException wewnątrz, a następnie używają lokalizatora do ponownej oceny i uzyskania nowego obiektu WebElement. W ten sposób musisz rozprowadzić kod obsługujący wyjątek na całej bazie kodu i zlokalizować go w jednej klasie.
Przyjrzę się open sourcing tylko tych kilku klas wkrótce i dodać link tutaj, jeśli jesteś zainteresowany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-25 10:10:03
Ten wyjątek jest wyrzucany, gdy próbujesz użyć metody WebElement, która nie jest już na stronie. Jeśli twoja siatka dynamicznie ładuje dane i odświeżasz siatkę, wszelkie odniesienia do elementów na tej siatce będą "przestarzałe". Sprawdź dwukrotnie, czy element, do którego próbujesz się odwołać, znajduje się na stronie w testach i może być konieczne ponowne utworzenie instancji obiektu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-31 16:49:17
Napotkał również ten problem, wygląda na to, że bardzo oczywiste jest, że ładowanie panelu modalnego wpada w stan wyścigu i czeka do końca czasu.
Próbowałem wiele razy i okazało się, że rozwiązaniem jest wstrzymanie ładowania panelu modalnego do momentu, aż będzie on dokładnie znaleziony przez webDriver i jednocześnie odświeżanie instancji webDriver , a następnie spróbuj znaleźć WebElements w panelu modalnym.
Więc rozwiązanie wygląda następująco: np. MyModalPanel jest Twoim ID ModalPanel, następnie wykonaj następujące
page.openModalPanel();
Assert.assertTrue(page.waitTillDisplay( "MyModalPanelContentDiv"), Wait.MODAL_PANEL));
page.fillInFormInModalpanel(formObj);
A kod waitTillDisplay można znaleźć na stronie WebDriver, po prostu wkleję mój kod tutaj w celach informacyjnych:
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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-07 06:55:43
Możesz próbować uzyskać dowolne właściwości elementu po kliknięciu elementu.
Miałem ten sam problem, próbowałem uzyskać tekst () przycisku po jego kliknięciu. W moim przypadku po kliknięciu przycisku pojawia się nowe okno.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-04 10:47:58
Użyłem FluentWait i również ExpectedCondition apply override: https://gist.github.com/djangofan/5112655 . Ten obsługuje wyjątek wewnątrz sfinalizowanego bloku, w przeciwieństwie do tego, jak inni ludzie na to odpowiadają, i pozwala na zawinięcie kolejnych prób w ten blok. Myślę, że to jest bardziej eleganckie.
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.");
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-13 22:36: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);
}
/ / a poniżej znajduje się metoda master, która obsługuje StaleElementReferenceException
i inne wyjątki.
/ / w sekcji catch zastąp (Exception e)
na (StaleElementReferenceException e)
, Jeśli chcesz, aby ta metoda ponownie próbowała akcji (takich jak click, sendkeys itp.) tylko StaleElementReferenceException
, a nie inne wyjątki.
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's 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's 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's 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);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 14:09:07
Wprowadziłem kilka zmian, aby być bardziej elastycznym:
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());
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-08 12:17:26
W tym przypadku testy szukają elementu, który nie został jeszcze załadowany lub został odświeżony. W rezultacie, StaleElementException. Prostym rozwiązaniem byłoby dodanie fluentWait.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-22 18:02:20
Szybkie i brudne rozwiązanie:
el.click()
time.sleep(1)
Następnie kontynuuj analizę iteracji
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-17 15:54:43