selenium - Excepción StaleElementReference en PageFactory
selenium-webdriver pageobjects (3)
Estoy tratando de aprender el modelo de PageFactory.
Comprendí el hecho de que cuando hacemos un
initElements
, se encuentran los WebElements.
Digamos, por ejemplo, que hago clic en un elemento web y debido a que hay un cambio en uno de los otros elementos web en DOM.
Ahora, obviamente, obtendría una
StaleElementReferenceException
aquí.
¿Cómo resolvería este problema?
¿Debería encontrar ese WebElement específico nuevamente sabiendo el hecho de que puede haber un cambio en las propiedades del WebElement en el DOM? o hay otra forma de manejar esto?
StaleElementReferenceException
StaleElementReferenceException extiende WebDriverException e indica que la referencia anterior del elemento ahora está obsoleta y la referencia del elemento ya no está presente en el DOM de la página.
Razones comunes
-
Las razones comunes para enfrentar
StaleElementReferenceException
son las siguientes:- El elemento ha sido eliminado por completo.
- El elemento ya no está adjunto al DOM.
- Se ha actualizado la página web de la que formaba parte el elemento.
-
El elemento (anterior) ha sido eliminado por un
JavaScript
o
AjaxCall
y se reemplaza por un elemento (nuevo) con el mismo
ID
u otros atributos.
-
Solución
:
Si un elemento (antiguo) ha sido reemplazado por uno nuevo idéntico, la estrategia simple sería usar
findElement()
ofindElements
para buscar el elemento nuevamente.
Respondiendo tus consultas
-
Cuando hacemos un initElements, se encuentran los WebElements : cuando llamas
initElements()
métodoinitElements()
, todos los WebElements de esa página se inicializarán. Por ejemplo,LoginPageNew login_page = PageFactory.initElements(driver, LoginPageNew.class);
Esta línea de código inicializará todos los elementos web estáticos definidos dentro del alcance de
LoginPageNew.class
cada vez que se invoque desde su secuencia de comandos de automatización. -
Hago clic en un elemento web y debido a que hay un cambio en uno de los otros elementos web en DOM : esto es bastante posible.
-
Como ejemplo, en general, invocar
click()
en una etiqueta<input>
no desencadenaría ningún cambio de ninguno de los WebElements en el HTML DOM . -
Mientras que al invocar
click()
en una etiqueta<button>
o<a>
puede llamar a JavaScript o Ajax, que puede eliminar un elemento o puede reemplazar el elemento (anterior) por un elemento (nuevo) con el mismoID
u otro atributos.
-
Como ejemplo, en general, invocar
Conclusión
Entonces, si
WebDriver
arroja una
StaleElementReferenceException
, eso implica que aunque el elemento aún exista, la referencia se pierde.
Deberíamos descartar la referencia actual que tenemos y reemplazarla localizando el
WebElement
una vez más cuando se adjunte al DOM.
Eso significa que debe reinicializar nuevamente la clase a través del método
initElements()
que inturn reinicializa todos los
WebElements
definidos en esa página.
Solución
Si un elemento antiguo ha sido reemplazado por uno nuevo idéntico, la estrategia simple sería invocar la WebDriverWait con ExpectedConditions para buscar el elemento.
Puede encontrar discusiones detalladas relevantes en:
Referencias
Aquí están las referencias de esta discusión:
Este es un problema conocido con la implementación de PageFactory.
Si tiene la mala suerte de que el elemento se vuelva obsoleto en el instante entre el elemento que se encuentra, y luego se hace clic en el elemento, obtendrá este error. Lamentablemente, el código de PageFactory no intenta encontrar el elemento nuevamente si se ha vuelto obsoleto y genera una excepción.
Clasificaría esto como un error con PageFactory, debería volver a encontrar automáticamente el elemento si alguna vez se vuelve obsoleto (a menos que se use la anotación @CacheLookup).
La sugerencia de recuperar initElements no va a arreglar nada, solo necesita iniciar los elementos una vez porque eso vincula una clase de proxy Java al elemento en cuestión. Se supone que la implementación de la fábrica de páginas elimina la posibilidad de StaleElementReferenceExceptions (de ahí que esto sea un error)
Stale element exception
produce una
Stale element exception
en dos casos
El elemento ya no está adjunto al
DOM
.
El elemento ha sido eliminado por completo.
Cuando esto sucede, envuelve su código en
try catch block
luego puede repetir y volver a intentar tantas veces como sea necesario hasta que tenga éxito.
public void waitForElementPresent(final By by, int timeout){
WebDriverWait wait = (WebDriverWait)new WebDriverWait(driver,timeout)
.ignoring(StaleElementReferenceException.class);
wait.until(new ExpectedCondition<Boolean>(){
@Override
public Boolean apply(WebDriver webDriver) {
WebElement element = webDriver.findElement(by);
return element != null && element.isDisplayed();
}
});
}