van una reciclaje papelera los eliminar eliminados elimina duro donde disco directorio delete dela definitivamente contenido como celular carpeta borrar archivos archivo java selenium webdriver selenium-webdriver

java - una - ¿Cómo resolver, excepción de elemento obsoleto? si el elemento ya no está adjunto al DOM?



file.delete java no elimina (4)

Si está intentando hacer clic en el enlace, eso lo llevará a la página nueva. Después de eso navegando hacia atrás y haciendo clic en otros enlaces. Ellos debajo del código pueden ayudarte.

public int getNumberOfElementsFound(By by) { return driver.findElements(by).size(); } public WebElement getElementWithIndex(By by, int pos) { return driver.findElements(by).get(pos); } /**click on each link */ public void getLinks()throws Exception{ try { List<WebElement> componentList = driver.findElements(By.tagName("a")); System.out.println(componentList.size()); for (WebElement component : componentList) { //click1(); System.out.println(component.getAttribute("href")); } int numberOfElementsFound = getNumberOfElementsFound(By.tagName("a")); for (int pos = 0; pos < numberOfElementsFound; pos++) { if (getElementWithIndex(By.tagName("a"), pos).isDisplayed()){ getElementWithIndex(By.tagName("a"), pos).click(); Thread.sleep(200); driver.navigate().back(); Thread.sleep(200); } } }catch (Exception e){ System.out.println("error in getLinks "+e); } }

Tengo una pregunta con respecto a "El elemento ya no está adjunto al DOM".

Intenté diferentes soluciones, pero están funcionando intermitentemente. Por favor sugiera una solución que podría ser permanente.

WebElement getStaleElemById(String id, WebDriver driver) { try { return driver.findElement(By.id(id)); } catch (StaleElementReferenceException e) { System.out.println("Attempting to recover from StaleElementReferenceException ..."); return getStaleElemById(id, driver); } } WebElement getStaleElemByCss(String css, WebDriver driver) { try { return driver.findElement(By.cssSelector(css)); } catch (StaleElementReferenceException e) { System.out.println("Attempting to recover from StaleElementReferenceException ..."); return getStaleElemByCss(css, driver); } catch (NoSuchElementException ele) { System.out.println("Attempting to recover from NoSuchElementException ..."); return getStaleElemByCss(css, driver); } }

Gracias, Anu


El problema

El problema al que probablemente se enfrenta es que el método devuelve el elemento correcto (¡y válido!), Pero cuando intenta acceder a él un segundo después, es obsoleto y arroja.

Esto generalmente surge cuando:

  1. Hace clic en algo que carga una nueva página de forma asincrónica o al menos la cambia.
  2. Inmediatamente (antes de que la carga de la página pueda finalizar) busque un elemento ... ¡y lo encuentra!
  3. La página finalmente se descarga y la nueva se carga.
  4. Intenta acceder a su elemento previamente encontrado, pero ahora está desactualizado, aunque la nueva página también lo contenga.

Las soluciones

Hay cuatro formas de resolverlo, yo sé de:

  1. Use las esperas apropiadas

    Use las esperas adecuadas después de cada carga de página anticipada al hacer frente a páginas asincrónicas. Inserte una espera explícita después del clic inicial y espere a que se cargue la nueva página / contenido nuevo. Solo después de eso puedes intentar buscar el elemento que deseas. Esto debería ser lo primero que harás. Aumentará la solidez de sus pruebas en gran medida.

  2. La forma en que lo hiciste

    He estado usando una variante de su método durante dos años (junto con la técnica anterior en la solución 1) y funciona la mayor parte del tiempo y solo falla en extraños errores de WebDriver. Intente acceder al elemento encontrado inmediatamente después de encontrarlo (antes de regresar del método) a través de un método .isDisplayed() o algo así. Si arroja, ya sabes cómo buscar de nuevo. Si pasa, tienes una garantía más (falsa).

  3. Use un WebElement que se vuelva a encontrar cuando esté obsoleto

    Escriba un decorador WebElement que recuerde cómo se encontró y vuelva a encontrarlo cuando se acceda y se arroje. Esto obviamente te obliga a usar findElement() personalizados de findElement() que devolverían instancias de tu decorador (o, mejor aún, un WebDriver decorado que devolvería tus instancias de los findElement() usuales findElement() y findElemens() ). Hazlo asi:

    public class NeverStaleWebElement implements WebElement { private WebElement element; private final WebDriver driver; private final By foundBy; public NeverStaleWebElement(WebElement element, WebDriver driver, By foundBy) { this.element = element; this.driver = driver; this.foundBy = foundBy; } @Override public void click() { try { element.click(); } catch (StaleElementReferenceException e) { // log exception // assumes implicit wait, use custom findElement() methods for custom behaviour element = driver.findElement(foundBy); // recursion, consider a conditioned loop instead click(); } } // ... similar for other methods, too }

    Tenga en cuenta que si bien creo que la información foundBy debe ser accesible desde los WebElements genéricos para hacer esto más fácil, los desarrolladores de Selenium consideran que es un error intentar algo como esto y han decidido no hacer pública esta información . Podría decirse que es una mala práctica volver a encontrar elementos obsoletos, ya que está redescubriendo elementos implícitamente sin ningún mecanismo para verificar si está justificado. El mecanismo de redescubrimiento podría encontrar un elemento completamente diferente y no el mismo nuevamente. Además, falla horriblemente con findElements() cuando hay muchos elementos encontrados (es necesario no permitir volver a encontrar los elementos encontrados por findElements() , o recordar el cómo fue que su elemento fue de la List devuelta).

    Creo que a veces sería útil, pero es cierto que nadie usaría las opciones 1 y 2, que obviamente son soluciones mucho mejores para la solidez de sus pruebas. Úselos y solo cuando esté seguro de que necesita esto, vaya por ello.

  4. Use una cola de tareas (que puede volver a ejecutar tareas anteriores)

    ¡Implementa todo tu flujo de trabajo de una nueva manera!

    • Haga una cola central de trabajos para ejecutar. Haz que esta cola recuerde trabajos anteriores.
    • Implemente todas las tareas necesarias ("encuentre un elemento y haga clic en él", "encuentre un elemento y envíele claves", etc.) a través del modo Patrón de comando. Cuando se le llame, agregue la tarea a la cola central que luego (ya sea de forma sincrónica o asincrónica, no importa) la ejecuta.
    • @LoadsNewPage cada tarea con @LoadsNewPage , @Reversible , etc., según sea necesario.
    • La mayoría de sus tareas manejarán sus excepciones por sí mismas, deben ser autónomas.
    • Cuando la cola encuentre una excepción de elemento obsoleto, tomará la última tarea del historial de tareas y la volverá a ejecutar para volver a intentarlo.

    Obviamente, esto supondría un gran esfuerzo y, si no se lo considera muy bien, podría ser contraproducente pronto. Utilicé una variante (mucho más compleja y poderosa) de esto para reanudar las pruebas fallidas después de que arreglé manualmente la página en la que estaban. En algunas condiciones (por ejemplo, en una StaleElementException ), un error no finalizaría la prueba de inmediato, pero esperaría (antes de que finalice el tiempo de espera después de 15 segundos), aparecerá una ventana informativa y le dará al usuario la opción de actualizar manualmente la página / haga clic en el botón derecho / arregle el formulario / lo que sea. Luego volvería a ejecutar la tarea fallida o incluso le daría la posibilidad de retroceder algunos pasos en la historia (por ejemplo, hasta el último trabajo @LoadsNewPage ).

Nitpicks finales

Dicho todo esto, su solución original podría usar un poco de pulido. Puede combinar los dos métodos en uno, más general (o al menos delegar en este para reducir la repetición del código):

WebElement getStaleElem(By by, WebDriver driver) { try { return driver.findElement(by); } catch (StaleElementReferenceException e) { System.out.println("Attempting to recover from StaleElementReferenceException ..."); return getStaleElem(by, driver); } catch (NoSuchElementException ele) { System.out.println("Attempting to recover from NoSuchElementException ..."); return getStaleElem(by, driver); } }

Con Java 7, incluso un solo bloque de multicast sería suficiente:

WebElement getStaleElem(By by, WebDriver driver) { try { return driver.findElement(by); } catch (StaleElementReferenceException | NoSuchElementException e) { System.out.println("Attempting to recover from " + e.getClass().getSimpleName() + "..."); return getStaleElem(by, driver); } }

De esta forma, puede reducir en gran medida la cantidad de código que necesita mantener.


Resuelvo esto 1. manteniendo el elemento obsoleto y lo sondeo hasta que arroje una excepción, y luego 2. espere hasta que el elemento sea visible nuevamente.

boolean isStillOnOldPage = true; while (isStillOnOldPage) { try { theElement.getAttribute("whatever"); } catch (StaleElementReferenceException e) { isStillOnOldPage = false; } } WebDriverWait wait = new WebDriverWait(driver, 15); wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("theElementId")));


Soluciones para resolverlos:

  1. Almacenamiento de localizadores en sus elementos en lugar de referencias

driver = webdriver.Firefox(); driver.get("http://www.github.com"); search_input = lambda: driver.find_element_by_name(''q''); search_input().send_keys(''hello world/n''); time.sleep(5); search_input().send_keys(''hello frank/n'') // no stale element exception

  1. Ganchos de apalancamiento en las bibliotecas JS utilizadas

# Using Jquery queue to get animation queue length. animationQueueIs = """ return $.queue( $("#%s")[0], "fx").length; """ % element_id wait_until(lambda: self.driver.execute_script(animationQueueIs)==0)

  1. Transfiere tus acciones a la inyección de JavaScript

self.driver.execute_script("$(/"li:contains(''Narendra'')/").click()");

  1. Espere de manera proactiva para que el elemento quede obsoleto

# Wait till the element goes stale, this means the list has updated wait_until(lambda: is_element_stale(old_link_reference))

Esta solución, que funcionó para mí