¿Cómo forzar a Selenium WebDriver a hacer clic en un elemento que no está visible actualmente?

99

Estoy usando la API de Selenium 2 Java con FirefoxDriver. Cuando completo un formulario, se agregan casillas de verificación a la página según las entradas del formulario.

Me gustaría simular un clic en esas casillas de verificación usando Selenium. Los elementos son visibles y utilizables en un navegador normal, pero el selenio afirma que los elementos no son visibles.

"Element is not currently visible and so may not be interacted with"

¿Puedo obligar al selenio a ignorar el estado no visible de los elementos? ¿Cómo puedo obligar a Selenium a interactuar con el elemento no visible?

djondal
fuente
¿Qué navegador estás usando? No puede interactuar con elementos que están deshabilitados o no visibles porque un usuario final no podría interactuar con ellos. Deberá proporcionar su código de prueba y la fuente de la página si desea que intente diagnosticar el problema.
Ardesco

Respuestas:

102

Selenium determina que un elemento es visible o no según los siguientes criterios (use un inspector DOM para determinar qué CSS se aplica a su elemento, asegúrese de mirar el estilo calculado):

  • visibilidad! = oculta
  • display! = none (también se compara con cada elemento padre)
  • opacidad! = 0 (esto no está marcado para hacer clic en un elemento)
  • la altura y el ancho son ambos> 0
  • para una entrada, el tipo de atributo! = oculto

Tu elemento coincide con uno de esos criterios. Si no tiene la capacidad de cambiar el estilo del elemento, así es como puede hacerlo forzosamente con javascript (asumiremos WebDriver ya que dijo Selenium2 API):

((JavascriptExecutor)driver).executeScript("arguments[0].checked = true;", inputElement);

Pero eso no activará un evento de javascript, si depende del evento de cambio para esa entrada, tendrá que activarlo también (muchas formas de hacerlo, la más fácil es usar cualquier biblioteca de JavaScript que esté cargada en esa página).

La fuente para el control de visibilidad -

https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/dom.js#L577

La especificación de WebDriver que define esto:

https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#widl-WebElement-isDisplayed-boolean

lukeis
fuente
1
¿Tiene una fuente (o enlace canónico) para la lista de condiciones?
mjs
2
Siempre que pueda leer Javascript, el método bot.dom.isShown es lo que determina la visibilidad: code.google.com/p/selenium/source/browse/trunk/javascript/atoms/…
lukeis
qué es inputElement aquí. Ejecuto el siguiente código WebElement inputElement = driver.findElement (By.xpath (PASSWORD_PATH)); ((JavascriptExecutor) controlador) .executeScript ("argumentos [0] .checked = true;", inputElement); Pero no hay ayuda inputElement.sendKeys (contraseña);
Deepak Goel
2
@NIleshSharma python tiene el método execute_script directamente en el objeto del controlador: driver.execute_script (...)
lukeis
1
El enlace de fuente publicado por @TunaBum ha cambiado a code.google.com/p/selenium/source/browse/javascript/atoms/…
Shepmaster
27

A veces, esto significa que hay varios elementos en una página que tienen la misma propiedad por la que estás intentando buscar y estás "hablando con el incorrecto".

Si su elemento no se puede identificar de forma única por: id o: nombre (o: clase), podría ser complicado.

A veces, buscar el elemento por: xpath ayudará y, en algunos casos, incluso eso no es práctico.

En esos casos, es posible que deba obtener todos los elementos que coincidan con sus criterios y hacer referencia al correcto en el índice. Está sucio, pero funciona.

Estoy usando Selenium / Watir de la aplicación Ruby on Rails, así que en mi caso, el ejemplo sería:

browser = Watir::Browser.new(:firefox, :profile => "default")       
browser.goto("http://www.google.com/analytics")
# login
browser.divs(:text, "+ New Property").last.click

Espero que esto ayude.

ranktrackerpro
fuente
agregar una identificación al elemento dom lo arregló para mí
naoru
Tuve el mismo problema y ajustar el XPath para que pudiera distinguir un elemento único funcionó.
JohnL
Yo tuve el mismo problema. Se modificó la llamada a findElements () para contar coincidencias y había un elemento coincidente más. ¡Gracias!
Aries
Tanto esto para mí. SIEMPRE asegúrese de que sus criterios de selección sean lo suficientemente específicos para el elemento con el que cree que está interactuando. Muchas veces he tenido dos elementos en juego y uno está oculto y me da este error.
Chris
14

Tuve un problema similar, pero estaba relacionado con el elemento que no estaba visible en la ventana gráfica. Tomé una captura de pantalla y me di cuenta de que la ventana del navegador era demasiado estrecha y no se podía ver el elemento. Hice uno de estos y funcionó:

driver.maximize_window()

Ver: WebDriver.maximize_window ()

mynameistechno
fuente
7

O puede usar Selenium Action Class para simular la interacción del usuario, por ejemplo

    WebDriver = new FirefoxDriver();

    WebElement menu = driver.findElement(By.xpath("")); // the triger event element

    Actions build = new Actions(driver); // heare you state ActionBuider
    build.moveToElement(menu).build().perform(); // Here you perform hover mouse over the needed elemnt to triger the visibility of the hidden
    WebElement m2m= driver.findElement(By.xpath(""));//the previous non visible element
    m2m.click();
fil mihaylov
fuente
7

También hay otro caso en el que el elemento visible se reconocerá como no visible:

  • Cuando el elemento se transforma en CSS
  • Cuando el elemento principal del elemento se transforma en CSS

Para verificar si el elemento con el que no desea interactuar está transformado en CSS, en CHROME haga esto:

  1. inspector abierto
  2. Encuentre un elemento interesante (o más probablemente su elemento padre, supuestamente elemento div)
  3. Seleccione la pestaña 'Computado'
  4. si hay un parámetro: webkit-transform: matrix (...) significa que el elemento está transformado en CSS y puede que el selenio 2 no lo reconozca como un elemento visible
justnpT
fuente
5

La invisibilidad también puede deberse al momento en que se supone que el elemento debe aparecer lentamente. Forzar al navegador a esperar un poco podría ayudar en ese caso.

Consulte, por ejemplo, la pregunta sobre dejar que WebDriver espere hasta que un elemento esté presente .

avandeursen
fuente
2

Tuve el mismo problema con el selenio 2 en Internet Explorer 9, pero mi solución es realmente extraña. No pude hacer clic en las entradas dentro de mi formulario -> repeticiones de selenio, no son visibles.

Ocurrió cuando mi forma tenía sombras curvas -> http://www.paulund.co.uk/creating-different-css3-box-shadows-effects : en el concreto "Efecto no. 2"

No tengo idea de por qué y cómo esta solución de pseudoelemento detuvo las pruebas de selenio, pero funciona para mí.

Agoreddah
fuente
2

No puede forzar el acceso / cambio de elemento al que el usuario normalmente no tiene acceso, ya que Selenium está diseñado para imitar la interacción del usuario.

Si ocurre este error, verifique si:

  • elemento es visible en su ventana gráfica, intente maximizar la ventana actual que está usando webdriver (por ejemplo, maximize()en node.js ,maximize_window() en Python),
  • su elemento no aparece dos veces (bajo el mismo selector) y está seleccionando el incorrecto,
  • si su elemento está oculto, considere hacerlo visible,
  • si desea acceder / cambiar el valor del elemento oculto a pesar de la limitación, use Javascript para eso (por ejemplo, executeScript()en node.js , execute_script()en Python).
Kenorb
fuente
1
No tenía idea de que Selenium está diseñado para ser tan estricto. Parece que no es realmente una herramienta de automatización en el sentido general, sino más bien una herramienta automatizada de interacción con el usuario. Tiene un poco de sentido, supongo. ¡Gracias por aclararlo!
Daniel Lidström
1

Acabo de resolver este error mientras uso capibara en el proyecto ror agregando:

Capybara.ignore_elements = true

a features/support/env.rb.

Zernel
fuente
1

Acabo de resolver este error esperando la propiedad de visualización del elemento

waitFor() { element.displayed }
Suat Keskin
fuente
De todas las respuestas en esta página, esto es lo que solucionó mi problema con un cuadro de diálogo Bootstrap Modal. ¡Gracias @Suat Keskin!
alastairs
1

Entro en la excepción ElementNotVisibleException usando selenio para pruebas funcionales en un sitio de django con glifos de arranque como enlaces en plantillas como:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger"></span></a>

Durante mis pruebas funcionales, el estilo de arranque no se carga, luego intentar hacer clic en dichos enlaces generará ElementNotVisibleException. Me las arreglo para hacer que se pueda hacer clic simplemente agregando un espacio en la etiqueta, así:

<a href="{% url 'item-add' %}"><span class="glyphicon glyphicon-plus text-danger">&nbsp;</span></a>
jean pierre huart
fuente
1

Hay muchas buenas respuestas en esta página.

  1. Normalmente empiezo con maximizar.window (), de hecho hago esto en la fábrica de controladores o donde sea que inicialice su controlador. Esto es algo que se hace de forma predeterminada, siempre.
  2. Suele ser un elemento de espera debido a un retraso de JavaScript.

Ambos se analizan en varios detalles anteriormente. La respuesta que no vi fue ScrollToElement. Parece que está procesando una lista de elementos, mientras que mientras procesa está creando más elementos, casillas de verificación. Esto puede hacer que los elementos de su lista salgan de la página visible. A veces puede ver el elemento a simple vista, pero simplemente no puede hacer clic en él. Al procesar listas, a veces tiene que intervenir el desplazamiento.

  • Establezca un punto de interrupción y verifique si el elemento que está utilizando está en el borde de la ventana, arriba / abajo a la derecha / izquierda. A veces, cuando este es el caso, no puede acceder a él a través del selenio, pero puede hacer clic manualmente con el mouse.

Como me encontré con esto, creé un PageScroll.java y puse mis scripts de desplazamiento allí. Estos son algunos de los métodos de esta clase:

public static void scrollToTop(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0,0)");
    }

    public static void scrollToBottom(WebDriver driver) {
      ((JavascriptExecutor) driver)
        .executeScript("window.scrollTo(0, document.body.scrollHeight)");
    }

    public static void scrollToElementTop(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(true);", element);
    }

    public static void scrollToElementBottom(WebDriver driver, WebElement element) {
      ((JavascriptExecutor) driver).executeScript(
        "arguments[0].scrollIntoView(false);", element);
    }

consulte Desplazar elemento a la vista con selenio para obtener más ejemplos

mancocapac
fuente
0

La respuesta aceptada funcionó para mí. A continuación se muestra un código para encontrar el elemento padre que hace que Selenium piense que no es visible.

function getStyles(element){
	
	computedStyle = window.getComputedStyle(element);

	if(computedStyle.opacity === 0
	|| computedStyle.display === "none"
	|| computedStyle.visibility === "hidden"
	|| (computedStyle.height < 0 && computedStyle.height < 0)
	|| element.type === "hidden") {
		console.log("Found an element that Selenium will consider to not be visible")
		console.log(element);
		console.log("opacity: " + computedStyle.opacity);
		console.log("display: " + computedStyle.display);
		console.log("visibility: " + computedStyle.visibility);
		console.log("height: " + computedStyle.height);
		console.log("width: " + computedStyle.width);
	}

	if(element.parentElement){
		getStyles(element.parentElement);
	}
}

getStyles(document.getElementById('REPLACE WITH THE ID OF THE ELEMENT YOU THINK IS VISIBLE BUT SELENIUM CAN NOT FIND'));

estrellado
fuente
0

Para agregar mi granito de arena aquí: si un elemento reside detrás de un div fijo, se considerará como no visible y no podrá hacer clic en él; esto me sucedió recientemente y lo resolví ejecutando un script como se recomendó anteriormente, que hace:

document.evaluate("<xpath locator for element to be clicked>", document, null, XPathResult.ANY_TYPE, null).iterateNext().click()", locator);
Fernando Gabrieli
fuente
¿Qué es el localizador aquí?
Anjana