example - WebDriver click() vs JavaScript click()
protractor vs selenium (3)
Contrariamente a lo que sugiere la respuesta actualmente aceptada , no hay nada específico para PhantomJS cuando se trata de la diferencia entre hacer que WebDriver haga un clic y hacerlo en JavaScript.
La diferencia
La diferencia esencial entre los dos métodos es común a todos los navegadores y puede explicarse de manera bastante simple:
-
WebDriver: cuando WebDriver hace el clic, intenta lo mejor que puede simular lo que sucede cuando un usuario real usa el navegador. Suponga que tiene un elemento A que es un botón que dice "Haga clic en mí" y un elemento B que es un elemento
div
que es transparente pero tiene sus dimensiones yzIndex
configurados para que cubra completamente A. Luego le dice a WebDriver que haga clic en A. WebDriver simulará el clic para que B reciba el clic primero . ¿Por qué? Debido a que B cubre a A, y si un usuario intentara hacer clic en A, entonces B obtendría el evento primero. El hecho de que A finalmente obtenga el evento de clic depende de cómo B maneje el evento. En cualquier caso, el comportamiento con WebDriver en este caso es el mismo que cuando un usuario real intenta hacer clic en A. -
JavaScript: ahora, suponga que usa JavaScript para hacer
A.click()
. Este método de hacer clic no reproduce lo que realmente sucede cuando el usuario intenta hacer clic en A. JavaScript envía el evento declick
directamente a A, y B no obtendrá ningún evento.
¿Por qué funciona un clic de JavaScript cuando no funciona un clic de WebDriver?
Como mencioné anteriormente, WebDriver intentará simular lo mejor que pueda lo que sucede cuando un usuario real está usando un navegador. El hecho es que el DOM puede contener elementos con los que un usuario no puede interactuar, y WebDriver no le permitirá hacer clic en estos elementos. Además del caso superpuesto que mencioné, esto también implica que no se puede hacer clic en elementos invisibles. Un caso común que veo en las preguntas de desbordamiento de pila es alguien que está tratando de interactuar con un elemento de la GUI que ya existe en el DOM pero que se vuelve visible solo cuando se ha manipulado algún otro elemento. Esto sucede a veces con los menús desplegables: primero debe hacer clic en el botón que abre el menú desplegable antes de que se pueda seleccionar un elemento del menú. Si alguien intenta hacer clic en el elemento del menú antes de que el menú sea visible, WebDriver se negará y dirá que el elemento no puede ser manipulado. Si la persona intenta hacerlo con JavaScript, funcionará porque el evento se entrega directamente al elemento, independientemente de la visibilidad.
¿Cuándo debe usar JavaScript para hacer clic?
Si está utilizando Selenium para probar una aplicación , mi respuesta a esta pregunta es "casi nunca". En general, su prueba de Selenium debería reproducir lo que un usuario haría con el navegador. Tomando el ejemplo del menú desplegable: una prueba debe hacer clic en el botón que abre primero el menú desplegable y luego hacer clic en el elemento del menú. Si hay un problema con la GUI porque el botón es invisible, o el botón no muestra los elementos del menú, o algo similar, entonces su prueba fallará y habrá detectado el error. Si usa JavaScript para hacer clic, no podrá detectar estos errores a través de pruebas automatizadas.
Digo "casi nunca" porque puede haber excepciones en las que tiene sentido usar JavaScript. Sin embargo, deberían ser muy raros.
Si está utilizando Selenium para eliminar sitios , entonces no es tan importante intentar reproducir el comportamiento del usuario. Por lo tanto, usar JavaScript para omitir la GUI es un problema menor.
La historia:
Aquí en StackOverflow, he visto a usuarios que informan que no pueden hacer clic en un elemento mediante el comando "clic" de selenium WebDriver y pueden solucionarlo con un clic de JavaScript ejecutando un script.
Ejemplo en Python:
element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)
Ejemplo en WebDriverJS / Protractor:
var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());
La pregunta:
¿Por qué hacer clic en "a través de JavaScript" funciona cuando un clic en WebDriver normal no funciona? ¿Cuándo exactamente está sucediendo esto y cuál es la desventaja de esta solución (si la hay)?
Personalmente utilicé esta solución sin comprender por qué tengo que hacerlo y a qué problemas puede conducir.
El clic ejecutado por el controlador intenta simular el comportamiento de un usuario real lo más cerca posible mientras el JavaScript
HTMLElement.click()
realiza la acción predeterminada para el evento de
click
, incluso si el elemento no es interactivo.
Las diferencias son:
-
El controlador se asegura de que el elemento sea visible desplazándolo hacia la vista y verifica que el elemento sea interactivo .
El controlador generará un error:
- cuando el elemento en la parte superior en las coordenadas del clic no es el elemento objetivo o un descendiente
- cuando el elemento no tiene un tamaño positivo o si es completamente transparente
-
cuando el elemento es una entrada o botón deshabilitado (el atributo / propiedad
disabled
estrue
) -
cuando el elemento tiene el puntero del mouse deshabilitado (CSS
pointer-events
esnone
)
Un JavaScriptHTMLElement.click()
siempre realizará la acción predeterminada o, en el mejor de los casos, fallará silenciosamente si el elemento está deshabilitado.
-
Se espera que el controlador ponga el elemento en foco si es enfocable.
Un JavaScript
HTMLElement.click()
no lo hará.
-
Se espera que el controlador emita todos los eventos (mousemove, mousedown, mouseup, click, ...) como un usuario real.
Un JavaScript
HTMLElement.click()
emite solo el eventoclick
. La página puede confiar en estos eventos adicionales y puede comportarse de manera diferente si no se emiten.Estos son los eventos emitidos por el controlador para un clic con Chrome:
mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... } click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
Y este es el evento emitido con una inyección de JavaScript:
click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
-
El evento emitido por un JavaScript
.click()
no es confiable y la acción predeterminada no se puede invocar:https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted
https://googlechrome.github.io/samples/event-istrusted/index.htmlTenga en cuenta que algunos de los controladores siguen generando eventos no confiables. Este es el caso de PhantomJS a partir de la versión 2.1.
-
El evento emitido por un JavaScript
.click()
no tiene las coordenadas del clic .Las propiedades
clientX, clientY, screenX, screenY, layerX, layerY
se establecen en0
. La página puede depender de ellos y comportarse de manera diferente.
Puede estar bien usar un JavaScript
.click()
para eliminar algunos datos, pero no está en un contexto de prueba.
Derrota el propósito de la prueba ya que no simula el comportamiento de un usuario.
Por lo tanto, si falla el clic del controlador, lo más probable es que un usuario real tampoco realice el mismo clic en las mismas condiciones.
¿Qué hace que el controlador no haga clic en un elemento cuando esperamos que tenga éxito?
-
El elemento objetivo aún no es visible / interactible debido a un retraso o un efecto de transición.
Algunos ejemplos :
https://developer.mozilla.org/fr/docs/Web (menú desplegable de navegación) http://materializecss.com/side-nav.html (barra lateral desplegable)
Lugares de trabajo:
Agregue un camarero para esperar la visibilidad, un tamaño mínimo o una posición estable:
// wait visible browser.wait(ExpectedConditions.visibilityOf(elem), 5000); // wait visible and not disabled browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000); // wait for minimum width browser.wait(function minimumWidth() { return elem.getSize().then(size => size.width > 50); }, 5000);
Vuelva a intentar hacer clic hasta que tenga éxito:
browser.wait(function clickSuccessful() { return elem.click().then(() => true, (ex) => false); }, 5000);
Agregue un retraso que coincida con la duración de la animación / transición:
browser.sleep(250);
-
El elemento objetivo termina cubierto por un elemento flotante una vez que se desplaza hacia la vista:
El controlador desplaza automáticamente el elemento hacia la vista para que sea visible. Si la página contiene un elemento flotante / adhesivo (menú, anuncios, pie de página, notificación, política de cookies ...), el elemento puede quedar cubierto y dejará de ser visible / interactivo.
Ejemplo: https://twitter.com/?lang=en
Soluciones alternativas:
Establezca el tamaño de la ventana en una más grande para evitar el desplazamiento o el elemento flotante.
Mover sobre el elemento con un desplazamiento negativo
Y
y luego hacer clic en él:browser.actions() .mouseMove(elem, {x: 0, y: -250}) .click() .perform();
Desplace el elemento hacia el centro de la ventana antes del clic:
browser.executeScript(function scrollCenter(elem) { var win = elem.ownerDocument.defaultView || window, box = elem.getBoundingClientRect(), dy = box.top - (win.innerHeight - box.height) / 2; win.scrollTo(win.pageXOffset, win.pageYOffset + dy); }, element); element.click();
Ocultar el elemento flotante si no se puede evitar:
browser.executeScript(function scrollCenter(elem) { elem.style.display = ''none''; }, element);
NOTA: llamemos ''clic'' es clic del usuario final. ''js click'' es clic a través de JS
¿Por qué hacer clic en "a través de JavaScript" funciona cuando un clic en WebDriver normal no funciona?
Hay 2 casos para que esto suceda:
I. Si está usando PhamtomJS
Entonces este es el comportamiento más común conocido de
PhantomJS
.
Algunos elementos a veces no se pueden hacer clic, por ejemplo
<div>
.
Esto se debe a que
PhantomJS
fue
PhantomJS
originalmente para simular el motor de los navegadores (como HTML + CSS inicial -> computación CSS -> representación).
Pero no significa interactuar con el usuario final (ver, hacer clic, arrastrar).
Por
PhamtomJS
tanto,
PhamtomJS
solo es parcialmente compatible con la interacción de los usuarios finales.
¿POR QUÉ JS HACE CLIC EN EL TRABAJO?
En cuanto a cualquier clic, todos son clic medio.
Es como una pistola con
1 cañón
y
2 disparadores
.
Uno de la ventana gráfica, uno de JS.
Dado que
PhamtomJS
excelente para simular el motor del navegador, un clic JS debería funcionar perfectamente.
II El controlador de eventos de "clic" debe vincularse en el mal período de tiempo.
Por ejemplo, tenemos un
<div>
-
-> Hacemos un cálculo
-
-> luego vinculamos el evento de clic al
<div>
. -
-> Además con una codificación incorrecta de angular (por ejemplo, no manejar el ciclo del osciloscopio correctamente)
Podemos terminar con el mismo resultado. Hacer clic no funcionará porque WebdriverJS intenta hacer clic en el elemento cuando no tiene un controlador de eventos de clic.
¿POR QUÉ JS HACE CLIC EN EL TRABAJO? Js click es como inyectar js directamente en el navegador. Posible de 2 maneras,
El puño es a través de la consola de devtools (sí, WebdriverJS se comunica con la consola de devtools).
El segundo
es inyectar una etiqueta
<script>
directamente en HTML.
Para cada navegador, el comportamiento será diferente. Pero independientemente, estos métodos son más complicados que hacer clic en el botón. Click está usando lo que ya está allí (clic de usuarios finales), js click está pasando por la puerta trasera.
Y para js click parecerá ser una tarea asincrónica. Esto está relacionado con un tema un poco complejo de '' tarea asíncrona del navegador y programación de tareas de la CPU '' (léelo hace un tiempo no puedo encontrar el artículo nuevamente). Para abreviar, esto resultará principalmente ya que js click tendrá que esperar un ciclo de programación de tareas de la CPU y se ejecutará un poco más lento después del enlace del evento click. (Podría conocer este caso cuando encontró que el elemento a veces se puede hacer clic, a veces no).
¿Cuándo exactamente está sucediendo esto y cuál es la desventaja de esta solución (si la hay)?
=> Como se mencionó anteriormente, ambos significan para un propósito, pero sobre el uso de qué entrada:
- Haga clic: está utilizando lo que proporciona por defecto del navegador.
- JS click: está pasando por la puerta trasera.
=> Para el rendimiento, es difícil de decir porque se basa en los navegadores. Pero en general:
- Clic: no significa más rápido, pero solo firmó una posición más alta en la lista de programación de la tarea de ejecución de la CPU.
- Clic de JS: no significa más lento, pero solo inició sesión en la última posición de la lista de tareas de CPU.
=> Desventajas:
- Clic: no parece tener ningún inconveniente, excepto que está utilizando PhamtomJS.
- JS click: muy malo para la salud. Puede hacer clic accidentalmente en algo que no aparece en la vista. Cuando use esto, asegúrese de que el elemento esté allí y disponible para ver y hacer clic como el punto de vista del usuario final.
PD: si estás buscando una solución.
- Usando PhantomJS? Sugeriré usar Chrome sin cabeza en su lugar. Sí, puedes configurar Chrome sin cabeza en Ubuntu. La cosa funciona igual que Chrome, pero solo no tiene una vista y tiene menos errores como PhantomJS.
-
¿No usa PhamtomJS pero aún tiene problemas?
Sugeriré usar ExpectedCondition of Protractor con
browser.wait()
( verifique esto para obtener más información )
(Quiero hacerlo breve, pero terminó mal. Cualquier cosa relacionada con la teoría es complicada de explicar ...)