Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusActions API
La Actions API de Selenium representa el núcleo para ejecutar interacciones complejas con elementos web que van más allá de las operaciones básicas como click()
y sendKeys()
. Esta API permite simular comportamientos de usuario avanzados que requieren una secuencia de acciones coordinadas, como combinaciones de teclas, movimientos de ratón precisos, o interacciones que involucran múltiples elementos simultáneamente.
La clase Actions
funciona como un constructor de secuencias que permite encadenar múltiples operaciones antes de ejecutarlas. Este enfoque resulta especialmente útil cuando necesitamos simular interacciones de usuario que requieren precisión temporal o coordinación entre diferentes tipos de entrada.
import org.openqa.selenium.interactions.Actions;
@Test
void inicializarActions() {
Actions actions = new Actions(driver);
// Las acciones se construyen pero no se ejecutan hasta llamar perform()
}
El patrón builder en Actions
La arquitectura de Actions sigue el patrón builder, permitiendo encadenar métodos de forma fluida. Cada método de acción devuelve la misma instancia de Actions
, facilitando la construcción de secuencias complejas de interacciones:
@Test
void ejemploPatronBuilder() {
WebElement elemento = driver.findElement(By.id("target"));
Actions actions = new Actions(driver);
actions.moveToElement(elemento)
.pause(Duration.ofMillis(500))
.click()
.perform(); // Ejecuta toda la secuencia
}
El método perform()
es fundamental en la API, ya que sin él, ninguna de las acciones definidas se ejecutará. Este diseño permite construir secuencias complejas de forma declarativa antes de su ejecución.
Gestión de timing y precisión
Una característica importante de la Actions API es su capacidad para controlar el timing entre acciones. El método pause()
permite introducir demoras específicas dentro de una secuencia, lo cual resulta crucial para simular comportamientos de usuario realistas:
@Test
void controlTiming() {
WebElement origen = driver.findElement(By.id("source"));
WebElement destino = driver.findElement(By.id("target"));
new Actions(driver)
.moveToElement(origen)
.pause(Duration.ofMillis(300))
.clickAndHold()
.pause(Duration.ofMillis(200))
.moveToElement(destino)
.release()
.perform();
}
Coordinación de múltiples dispositivos de entrada
La Actions API permite coordinar simultáneamente acciones de ratón y teclado, algo que no es posible with los métodos básicos de WebElement. Esta capacidad es esencial para interacciones avanzadas que requieren modificadores de teclado junto con acciones de ratón:
@Test
void accionesCoordinadas() {
WebElement elemento = driver.findElement(By.className("selectable"));
new Actions(driver)
.keyDown(Keys.CONTROL)
.click(elemento)
.keyUp(Keys.CONTROL)
.perform();
}
Esta coordinación precisa entre dispositivos de entrada permite simular comportamientos de usuario sofisticados que serían imposibles de replicar usando únicamente los métodos estándar de WebElement.
Contexto de ejecución y ámbito
Es importante comprender que cada instancia de Actions
mantiene su contexto de ejecución independiente. Las acciones se acumulan en una cola interna hasta que se invoca perform()
, momento en el cual se ejecutan secuencialmente en el orden definido:
@Test
void contextosIndependientes() {
Actions primeraSecuencia = new Actions(driver);
Actions segundaSecuencia = new Actions(driver);
// Cada Actions mantiene su propia secuencia
primeraSecuencia.click(elemento1).pause(Duration.ofMillis(100));
segundaSecuencia.doubleClick(elemento2);
// Se ejecutan independientemente
primeraSecuencia.perform();
segundaSecuencia.perform();
}
Esta independencia de contexto permite crear múltiples secuencias de acciones reutilizables dentro del mismo test, facilitando la organización del código y la reutilización de patrones de interacción comunes.
Mouse actions y keyboard actions
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
Acciones de ratón fundamentales
Las acciones de ratón en la Actions API proporcionan un control granular sobre el comportamiento del cursor, permitiendo simular interacciones precisas que los usuarios realizan en aplicaciones web modernas.
El método moveToElement()
constituye la base para muchas interacciones avanzadas, desplazando el cursor hacia un elemento específico sin realizar ninguna acción adicional. Esta funcionalidad es esencial para activar estados hover y preparar elementos para interacciones posteriores:
@Test
void movimientoBasicoRaton() {
WebElement menu = driver.findElement(By.className("dropdown-trigger"));
new Actions(driver)
.moveToElement(menu)
.perform();
// El elemento ahora tiene el estado hover activo
WebElement submenu = driver.findElement(By.className("dropdown-content"));
assertTrue(submenu.isDisplayed());
}
Para interacciones que requieren doble clic, el método doubleClick()
simula esta acción de forma nativa. Este comportamiento es común en interfaces que permiten editar contenido inline o activar funcionalidades específicas:
@Test
void dobleClicElemento() {
WebElement textoEditable = driver.findElement(By.className("editable-text"));
new Actions(driver)
.doubleClick(textoEditable)
.perform();
// Verificar que el modo edición se activó
WebElement campoInput = driver.findElement(By.tagName("input"));
assertTrue(campoInput.isDisplayed());
}
Menús contextuales y clic derecho
El método contextClick()
permite simular el clic derecho del ratón, activando menús contextuales que muchas aplicaciones web implementan para proporcionar opciones adicionales:
@Test
void menuContextual() {
WebElement elemento = driver.findElement(By.id("context-target"));
new Actions(driver)
.contextClick(elemento)
.perform();
// Verificar que el menú contextual apareció
WebElement menuContexto = driver.findElement(By.className("context-menu"));
assertTrue(menuContexto.isDisplayed());
// Seleccionar una opción del menú
WebElement opcion = driver.findElement(By.xpath("//li[text()='Copiar']"));
opcion.click();
}
Operaciones de arrastre con clickAndHold
El método clickAndHold()
inicia una operación de arrastre manteniendo presionado el botón del ratón sobre un elemento. Esta acción se combina frecuentemente con moveToElement()
y release()
para crear interacciones de arrastre complejas:
@Test
void inicioArrastre() {
WebElement elementoArrastrable = driver.findElement(By.className("draggable"));
WebElement zonaDestino = driver.findElement(By.className("drop-zone"));
new Actions(driver)
.clickAndHold(elementoArrastrable)
.moveToElement(zonaDestino)
.release()
.perform();
}
Acciones de teclado con modificadores
Las acciones de teclado permiten simular combinaciones de teclas complejas utilizando modificadores como Control, Shift y Alt. Los métodos keyDown()
y keyUp()
proporcionan control preciso sobre cuándo se presionan y sueltan las teclas modificadoras:
@Test
void combinacionesTeclado() {
WebElement campoTexto = driver.findElement(By.id("texto-input"));
campoTexto.click();
campoTexto.sendKeys("Texto de ejemplo");
// Seleccionar todo el texto con Ctrl+A
new Actions(driver)
.keyDown(Keys.CONTROL)
.sendKeys("a")
.keyUp(Keys.CONTROL)
.perform();
// Copiar el texto seleccionado
new Actions(driver)
.keyDown(Keys.CONTROL)
.sendKeys("c")
.keyUp(Keys.CONTROL)
.perform();
}
Modificadores múltiples y secuencias complejas
La Actions API permite combinar múltiples modificadores simultáneamente, lo cual es útil para atajos de teclado avanzados que requieren varias teclas especiales:
@Test
void modificadoresMultiples() {
WebElement editor = driver.findElement(By.className("code-editor"));
editor.click();
// Comentar línea con Ctrl+Shift+/
new Actions(driver)
.keyDown(Keys.CONTROL)
.keyDown(Keys.SHIFT)
.sendKeys("/")
.keyUp(Keys.SHIFT)
.keyUp(Keys.CONTROL)
.perform();
}
Navegación con teclas especiales
Las teclas de navegación como las flechas direccionales, Tab, Enter y Escape se manejan através de la clase Keys
, permitiendo simular navegación por teclado en interfaces complejas:
@Test
void navegacionTeclado() {
WebElement primerElemento = driver.findElement(By.className("focusable"));
primerElemento.click();
// Navegar entre elementos con Tab
new Actions(driver)
.sendKeys(Keys.TAB)
.sendKeys(Keys.TAB)
.sendKeys(Keys.ENTER)
.perform();
// Navegar en menús con flechas
new Actions(driver)
.sendKeys(Keys.ARROW_DOWN)
.sendKeys(Keys.ARROW_DOWN)
.sendKeys(Keys.ENTER)
.perform();
}
Casos de uso empresariales
En aplicaciones empresariales, estas acciones son fundamentales para automatizar workflows complejos. Por ejemplo, la gestión de selecciones múltiples en tablas de datos:
@Test
void seleccionMultipleTabla() {
List<WebElement> filas = driver.findElements(By.cssSelector("table tr"));
// Seleccionar primera fila
new Actions(driver)
.click(filas.get(1))
.perform();
// Añadir segunda fila a la selección con Ctrl+click
new Actions(driver)
.keyDown(Keys.CONTROL)
.click(filas.get(3))
.keyUp(Keys.CONTROL)
.perform();
// Extender selección con Shift+click
new Actions(driver)
.keyDown(Keys.SHIFT)
.click(filas.get(5))
.keyUp(Keys.SHIFT)
.perform();
}
Combinación de acciones de ratón y teclado
La potencia real de la Actions API se manifiesta cuando combinamos acciones de ratón y teclado en secuencias coordinadas que replican comportamientos de usuario sofisticados:
@Test
void interaccionCompleja() {
WebElement lienzo = driver.findElement(By.id("drawing-canvas"));
// Dibujar manteniendo Shift para líneas rectas
new Actions(driver)
.moveToElement(lienzo, 100, 100)
.keyDown(Keys.SHIFT)
.clickAndHold()
.moveByOffset(200, 0)
.release()
.keyUp(Keys.SHIFT)
.perform();
}
Drag and drop y hover
Operaciones de drag and drop nativas
Las operaciones de arrastre y soltado representan una de las interacciones más complejas en aplicaciones web modernas. Selenium proporciona métodos específicos que simplifican estas operaciones, eliminando la necesidad de construir manualmente secuencias con clickAndHold()
, moveToElement()
y release()
.
El método dragAndDrop()
ejecuta una operación completa de arrastre entre dos elementos en una sola llamada, manejando internamente toda la secuencia de acciones necesarias:
@Test
void dragAndDropBasico() {
WebElement elementoOrigen = driver.findElement(By.id("draggable-item"));
WebElement zonaDestino = driver.findElement(By.id("drop-target"));
new Actions(driver)
.dragAndDrop(elementoOrigen, zonaDestino)
.perform();
// Verificar que el elemento se movió correctamente
assertEquals("drop-target", elementoOrigen.findElement(By.xpath("./..")).getAttribute("id"));
}
Arrastre con desplazamiento por píxeles
Para casos donde no existe un elemento de destino específico, dragAndDropBy()
permite arrastrar un elemento desplazándolo por píxeles relativos a su posición actual. Esta funcionalidad es especialmente útil en editores gráficos, herramientas de diseño o interfaces de configuración visual:
@Test
void dragAndDropPorPixeles() {
WebElement slider = driver.findElement(By.className("range-slider-handle"));
// Mover el slider 150 píxeles hacia la derecha
new Actions(driver)
.dragAndDropBy(slider, 150, 0)
.perform();
// Verificar el nuevo valor del slider
String valorActual = slider.getAttribute("aria-valuenow");
assertTrue(Integer.parseInt(valorActual) > 50);
}
Drag and drop en listas reordenables
Una aplicación común del drag and drop es la reordenación de elementos en listas. Este patrón es frecuente en interfaces administrativas, paneles de control y aplicaciones de gestión de contenido:
@Test
void reordenarListaElementos() {
List<WebElement> elementos = driver.findElements(By.className("sortable-item"));
WebElement primerElemento = elementos.get(0);
WebElement tercerElemento = elementos.get(2);
// Mover el primer elemento a la tercera posición
new Actions(driver)
.dragAndDrop(primerElemento, tercerElemento)
.perform();
// Verificar el nuevo orden
List<WebElement> elementosActualizados = driver.findElements(By.className("sortable-item"));
assertNotEquals(primerElemento.getText(), elementosActualizados.get(0).getText());
}
Kanban boards y gestión de tareas
En aplicaciones empresariales tipo Kanban o gestores de proyectos, el drag and drop permite mover tareas entre diferentes estados o columnas:
@Test
void moverTareaKanban() {
WebElement tarea = driver.findElement(By.xpath("//div[@data-task-id='TASK-123']"));
WebElement columnaEnProceso = driver.findElement(By.className("column-in-progress"));
// Mover tarea de "To Do" a "In Progress"
new Actions(driver)
.dragAndDrop(tarea, columnaEnProceso)
.perform();
// Verificar que la tarea cambió de estado
WebElement tareaMovida = driver.findElement(By.xpath("//div[@data-task-id='TASK-123']"));
assertEquals("in-progress", tareaMovida.findElement(By.xpath("./..")).getAttribute("data-status"));
}
Efectos hover avanzados y navegación por menús
Los efectos hover van más allá del simple posicionamiento del cursor. En aplicaciones complejas, el hover puede activar animaciones, cargar contenido dinámico o revelar opciones de navegación anidadas:
@Test
void navegacionMenuMultinivel() {
WebElement menuPrincipal = driver.findElement(By.className("main-menu-item"));
// Activar el primer nivel del menú
new Actions(driver)
.moveToElement(menuPrincipal)
.perform();
// Esperar a que aparezca el submenu
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(3));
WebElement submenu = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.className("submenu-level-1")));
// Navegar al segundo nivel
WebElement itemSubmenu = submenu.findElement(By.className("submenu-item"));
new Actions(driver)
.moveToElement(itemSubmenu)
.perform();
// Verificar que el menú de tercer nivel apareció
WebElement submenuNivel2 = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.className("submenu-level-2")));
assertTrue(submenuNivel2.isDisplayed());
}
Tooltips y información contextual
El hover también activa tooltips informativos que proporcionan contexto adicional sobre elementos de la interfaz. Estos componentes son cruciales para la experiencia de usuario en aplicaciones complejas:
@Test
void verificarTooltipInformativo() {
WebElement iconoAyuda = driver.findElement(By.className("help-icon"));
new Actions(driver)
.moveToElement(iconoAyuda)
.perform();
// Verificar que el tooltip apareció con el contenido esperado
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(2));
WebElement tooltip = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.className("tooltip")));
String textoTooltip = tooltip.getText();
assertTrue(textoTooltip.contains("Esta función permite"));
}
Drag and drop con validación de zona válida
En interfaces sofisticadas, no todas las zonas permiten soltar elementos. Es importante validar que el drag and drop se realiza en áreas permitidas y manejar las restricciones correspondientes:
@Test
void dragAndDropConValidacion() {
WebElement documento = driver.findElement(By.className("document-item"));
WebElement carpetaValida = driver.findElement(By.cssSelector(".folder[data-accepts='documents']"));
WebElement carpetaInvalida = driver.findElement(By.cssSelector(".folder[data-accepts='images']"));
// Intentar arrastrar a zona inválida
new Actions(driver)
.dragAndDrop(documento, carpetaInvalida)
.perform();
// Verificar que el documento no se movió
assertFalse(carpetaInvalida.findElements(By.className("document-item")).size() > 0);
// Arrastrar a zona válida
new Actions(driver)
.dragAndDrop(documento, carpetaValida)
.perform();
// Verificar que el movimiento fue exitoso
assertTrue(carpetaValida.findElements(By.className("document-item")).size() > 0);
}
Interacciones complejas con timing controlado
Algunas aplicaciones requieren timing específico durante las operaciones de drag and drop, especialmente cuando hay animaciones o efectos visuales que deben completarse:
@Test
void dragAndDropConTiming() {
WebElement elementoComplejo = driver.findElement(By.className("animated-item"));
WebElement zonaEspecial = driver.findElement(By.className("special-drop-zone"));
new Actions(driver)
.clickAndHold(elementoComplejo)
.pause(Duration.ofMillis(500)) // Esperar animación de inicio
.moveToElement(zonaEspecial)
.pause(Duration.ofMillis(300)) // Permitir detección de zona válida
.release()
.perform();
// Verificar el resultado después de las animaciones
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(3));
wait.until(ExpectedConditions.attributeContains(elementoComplejo, "class", "dropped"));
}
Hover con efectos de carga dinámica
En aplicaciones modernas, el hover puede disparar cargas de contenido desde el servidor. Estos casos requieren esperas específicas para verificar que el contenido se cargó correctamente:
@Test
void hoverConCargaDinamica() {
WebElement tarjetaUsuario = driver.findElement(By.className("user-card"));
new Actions(driver)
.moveToElement(tarjetaUsuario)
.perform();
// Esperar a que se cargue información adicional del usuario
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
WebElement perfilCompleto = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.className("user-profile-expanded")));
// Verificar que se cargaron datos específicos
WebElement estadisticas = perfilCompleto.findElement(By.className("user-stats"));
assertTrue(estadisticas.findElements(By.className("stat-item")).size() > 0);
}
Casos de uso en editores visuales
Los editores visuales representan uno de los contextos más exigentes para drag and drop, requiriendo precisión píxel por píxel y manejo de múltiples tipos de elementos:
@Test
void editorVisualDragAndDrop() {
WebElement componenteTexto = driver.findElement(By.className("component-text"));
WebElement lienzo = driver.findElement(By.id("design-canvas"));
// Arrastrar componente al lienzo en posición específica
new Actions(driver)
.dragAndDropBy(componenteTexto, 250, 180)
.perform();
// Verificar que el componente se posicionó correctamente
WebElement componenteEnLienzo = lienzo.findElement(By.className("component-text"));
String posicionX = componenteEnLienzo.getCssValue("left");
String posicionY = componenteEnLienzo.getCssValue("top");
assertTrue(posicionX.contains("250"));
assertTrue(posicionY.contains("180"));
}
Aprendizajes de esta lección de Selenium
- Comprender el funcionamiento y arquitectura de la Actions API en Selenium.
- Aprender a construir y ejecutar secuencias complejas de acciones con el patrón builder.
- Controlar el timing y la precisión en interacciones avanzadas.
- Dominar acciones de ratón y teclado, incluyendo combinaciones y modificadores.
- Aplicar técnicas de drag and drop y efectos hover en escenarios reales y empresariales.
Completa este curso de Selenium y certifícate
Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs