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 PlusXPath básico
XPath (XML Path Language) es un lenguaje de consulta que permite navegar y seleccionar nodos en documentos HTML y XML. En el contexto de Selenium WebDriver, XPath se convierte en una herramienta fundamental para localizar elementos web de manera precisa y flexible.
La sintaxis XPath utiliza una estructura similar a las rutas de archivos en sistemas operativos, donde cada nivel del DOM se representa mediante barras inclinadas. Esta aproximación permite construir expresiones que describen la ubicación exacta de un elemento dentro de la estructura jerárquica del documento.
Diferencias entre XPath absoluto y relativo
XPath absoluto define la ruta completa desde la raíz del documento hasta el elemento objetivo. Esta aproximación comienza siempre con una barra inclinada simple (/
) y especifica cada nivel del DOM:
@Test
void ejemploXPathAbsoluto() {
WebElement elemento = driver.findElement(By.xpath("/html/body/div[1]/form/input[2]"));
elemento.sendKeys("Texto de prueba");
}
Sin embargo, esta técnica presenta limitaciones significativas en entornos de desarrollo ágiles. Cualquier modificación en la estructura HTML invalida completamente el selector, generando pruebas frágiles y difíciles de mantener.
XPath relativo ofrece una alternativa más robusta mediante el uso de doble barra inclinada (//
). Esta sintaxis permite localizar elementos independientemente de su posición exacta en el DOM:
@Test
void ejemploXPathRelativo() {
WebElement elemento = driver.findElement(By.xpath("//input[@type='email']"));
elemento.click();
}
Navegación básica con barras inclinadas
La navegación descendente utiliza la barra inclinizada simple (/
) para seleccionar hijos directos de un nodo:
@Test
void navegacionDescendente() {
// Selecciona el primer párrafo dentro de un div específico
WebElement parrafo = driver.findElement(By.xpath("//div[@class='content']/p"));
String texto = parrafo.getText();
assertThat(texto).isNotEmpty();
}
La navegación en cualquier descendiente emplea la doble barra (//
) para buscar elementos en cualquier nivel de profundidad:
@Test
void navegacionCualquierDescendiente() {
// Localiza un botón en cualquier lugar dentro de un formulario
WebElement boton = driver.findElement(By.xpath("//form//button[@type='submit']"));
boton.click();
}
Selección por atributos
Los corchetes ([]
) permiten aplicar filtros basados en atributos o posición. La sintaxis @atributo
accede directamente a las propiedades de los elementos:
@Test
void seleccionPorAtributos() {
// Localiza por ID
WebElement porId = driver.findElement(By.xpath("//input[@id='usuario']"));
// Localiza por clase CSS
WebElement porClase = driver.findElement(By.xpath("//div[@class='mensaje-error']"));
// Localiza por atributo personalizado
WebElement porDataAttr = driver.findElement(By.xpath("//button[@data-action='guardar']"));
}
Funciones de texto básicas
La función **text()**
permite localizar elementos basándose en su contenido textual exacto:
@Test
void localizacionPorTexto() {
// Localiza un enlace por su texto exacto
WebElement enlace = driver.findElement(By.xpath("//a[text()='Iniciar sesión']"));
enlace.click();
// Localiza un encabezado específico
WebElement titulo = driver.findElement(By.xpath("//h2[text()='Panel de control']"));
assertThat(titulo.isDisplayed()).isTrue();
}
La función **contains()**
ofrece mayor flexibilidad al permitir coincidencias parciales en texto y atributos:
@Test
void localizacionConContains() {
// Busca elementos que contengan texto parcial
WebElement boton = driver.findElement(By.xpath("//button[contains(text(), 'Confirmar')]"));
// Filtra por clases CSS que contengan una palabra específica
WebElement elemento = driver.findElement(By.xpath("//div[contains(@class, 'activo')]"));
// Combina múltiples condiciones
WebElement input = driver.findElement(
By.xpath("//input[contains(@placeholder, 'correo') and @type='email']")
);
}
Selección por posición
Los índices numéricos dentro de los corchetes permiten seleccionar elementos específicos cuando existen múltiples coincidencias:
@Test
void seleccionPorPosicion() {
// Selecciona el primer elemento de una lista
WebElement primerItem = driver.findElement(By.xpath("//ul/li[1]"));
// Selecciona el tercer párrafo de un artículo
WebElement tercerParrafo = driver.findElement(By.xpath("//article/p[3]"));
// Obtiene todos los elementos y selecciona uno específico
List<WebElement> opciones = driver.findElements(By.xpath("//select/option"));
WebElement segundaOpcion = opciones.get(1); // Índice basado en 0
}
Combinación de criterios
La versatilidad de XPath permite combinar múltiples criterios de selección para localizar elementos con mayor precisión:
@Test
void criteriosCombinados() {
// Combina atributo y posición
WebElement elemento = driver.findElement(
By.xpath("//table[@id='datos']/tbody/tr[2]/td[@class='precio']")
);
// Utiliza múltiples condiciones con operadores lógicos
WebElement input = driver.findElement(
By.xpath("//input[@type='text' and @required and contains(@name, 'usuario')]")
);
// Selecciona elementos hermanos específicos
WebElement hermano = driver.findElement(
By.xpath("//label[text()='Email']/following-sibling::input")
);
}
Esta sintaxis fundamental de XPath proporciona las herramientas necesarias para localizar elementos web de manera efectiva. La comprensión de estos conceptos básicos establece la base sólida para técnicas más avanzadas de selección y navegación en el DOM.
XPath avanzado
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
La sintaxis avanzada de XPath extiende las capacidades básicas de localización mediante técnicas sofisticadas que permiten navegar con precisión por estructuras DOM complejas. Estas técnicas resultan especialmente valiosas cuando los selectores básicos no proporcionan la especificidad necesaria para identificar elementos únicos.
Ejes de navegación (Axes)
Los ejes XPath definen la dirección de navegación desde un nodo de contexto hacia otros nodos relacionados en el árbol DOM. Esta funcionalidad permite localizar elementos basándose en su relación estructural rather than en su posición absoluta.
El eje **parent**
navega hacia el elemento contenedor directo:
@Test
void navegacionPadre() {
// Localiza el formulario que contiene un input específico
WebElement formulario = driver.findElement(
By.xpath("//input[@id='email']/parent::form")
);
// Verifica que el formulario tenga la clase correcta
assertThat(formulario.getAttribute("class")).contains("login-form");
}
El eje **child**
selecciona elementos hijos directos, ofreciendo mayor precisión que la barra inclinada simple:
@Test
void navegacionHijo() {
// Selecciona solo los párrafos que son hijos directos
List<WebElement> parrafosDirectos = driver.findElements(
By.xpath("//article/child::p")
);
// Localiza el primer botón hijo de un div específico
WebElement primerBoton = driver.findElement(
By.xpath("//div[@class='actions']/child::button[1]")
);
}
Los ejes **following-sibling**
y **preceding-sibling**
navegan entre elementos hermanos:
@Test
void navegacionHermanos() {
// Localiza el input que sigue a una etiqueta específica
WebElement inputPassword = driver.findElement(
By.xpath("//label[text()='Contraseña']/following-sibling::input")
);
// Encuentra el elemento anterior a un botón específico
WebElement elementoPrevio = driver.findElement(
By.xpath("//button[@type='submit']/preceding-sibling::input")
);
inputPassword.sendKeys("password123");
}
Los ejes **following**
y **preceding**
extienden la búsqueda a todos los elementos que aparecen después o antes en el documento:
@Test
void navegacionDocumento() {
// Localiza el primer enlace que aparece después de un encabezado
WebElement enlaceSiguiente = driver.findElement(
By.xpath("//h2[text()='Productos']/following::a[1]")
);
// Encuentra un elemento de error que precede a un formulario
WebElement mensajeError = driver.findElement(
By.xpath("//form[@id='registro']/preceding::div[@class='error'][1]")
);
}
Operadores lógicos avanzados
Los operadores lógicos permiten construir expresiones XPath complejas combinando múltiples condiciones de manera eficiente.
El operador **and**
requiere que todas las condiciones se cumplan simultáneamente:
@Test
void operadorAnd() {
// Localiza inputs que cumplan múltiples criterios
WebElement inputComplejo = driver.findElement(
By.xpath("//input[@type='text' and @required and contains(@class, 'validate')]")
);
// Combina condiciones de texto y atributos
WebElement botonEspecifico = driver.findElement(
By.xpath("//button[contains(text(), 'Enviar') and @disabled='false']")
);
}
El operador **or**
permite que cualquiera de las condiciones sea verdadera:
@Test
void operadorOr() {
// Localiza elementos con diferentes tipos de input
WebElement campoTexto = driver.findElement(
By.xpath("//input[@type='email' or @type='text' or @type='tel']")
);
// Busca botones con diferentes textos posibles
WebElement botonAccion = driver.findElement(
By.xpath("//button[text()='Guardar' or text()='Actualizar' or text()='Crear']")
);
}
El operador **not**
excluye elementos que coincidan con la condición especificada:
@Test
void operadorNot() {
// Selecciona inputs que no estén deshabilitados
List<WebElement> inputsActivos = driver.findElements(
By.xpath("//input[not(@disabled)]")
);
// Localiza divs que no contengan una clase específica
WebElement divSinClase = driver.findElement(
By.xpath("//div[not(contains(@class, 'hidden'))]")
);
assertThat(inputsActivos).hasSizeGreaterThan(0);
}
Funciones de posición avanzadas
Las funciones de posición proporcionan capacidades sofisticadas para seleccionar elementos basándose en su ubicación relativa dentro de conjuntos de elementos similares.
La función **position()**
devuelve la posición numérica de un elemento dentro de su contexto:
@Test
void funcionPosition() {
// Selecciona elementos en posiciones pares
List<WebElement> filasPares = driver.findElements(
By.xpath("//table/tbody/tr[position() mod 2 = 0]")
);
// Localiza elementos después de la tercera posición
WebElement cuartoElemento = driver.findElement(
By.xpath("//ul/li[position() > 3][1]")
);
assertThat(filasPares).isNotEmpty();
}
La función **last()**
identifica el último elemento de un conjunto:
@Test
void funcionLast() {
// Selecciona el último elemento de una lista
WebElement ultimoItem = driver.findElement(
By.xpath("//nav/ul/li[last()]")
);
// Localiza el penúltimo párrafo de un artículo
WebElement penultimoParrafo = driver.findElement(
By.xpath("//article/p[last()-1]")
);
ultimoItem.click();
}
Combinación de funciones de posición para selecciones precisas:
@Test
void posicionesComplejas() {
// Selecciona los tres primeros elementos de cada sección
List<WebElement> primerosTres = driver.findElements(
By.xpath("//section//li[position() <= 3]")
);
// Localiza elementos en el rango central
WebElement elementoCentral = driver.findElement(
By.xpath("//table/tbody/tr[position() > 2 and position() < last()-1]")
);
}
XPath dinámico con variables
El XPath dinámico permite construir selectores adaptables que responden a condiciones cambiantes durante la ejecución de las pruebas.
Construcción de XPath con concatenación de cadenas:
@Test
void xpathDinamico() {
String tipoInput = "email";
String valorPlaceholder = "usuario@ejemplo.com";
// Construye XPath dinámicamente
String xpathDinamico = String.format(
"//input[@type='%s' and contains(@placeholder, '%s')]",
tipoInput, valorPlaceholder
);
WebElement inputDinamico = driver.findElement(By.xpath(xpathDinamico));
inputDinamico.clear();
}
Uso de variables para selección condicional:
@Test
void seleccionCondicional() {
boolean modoOscuro = true;
String claseEsperada = modoOscuro ? "dark-theme" : "light-theme";
WebElement contenedor = driver.findElement(
By.xpath("//div[contains(@class, '" + claseEsperada + "')]")
);
// Adapta la selección según el estado de la aplicación
String estadoBoton = contenedor.getAttribute("data-state");
String xpathCondicional = estadoBoton.equals("active")
? "//button[@data-action='pause']"
: "//button[@data-action='play']";
WebElement botonControl = driver.findElement(By.xpath(xpathCondicional));
botonControl.click();
}
Optimización y consideraciones de rendimiento
El rendimiento de XPath puede impactar significativamente en la velocidad de ejecución de las pruebas, especialmente en aplicaciones con DOM complejos.
Técnicas de optimización:
- Evita expresiones que comiencen con
**//**
cuando sea posible, utilizando selectores más específicos:
@Test
void optimizacionRendimiento() {
// Menos eficiente: búsqueda en todo el documento
// WebElement elemento = driver.findElement(By.xpath("//input[@type='email']"));
// Más eficiente: limita el alcance de búsqueda
WebElement formulario = driver.findElement(By.xpath("//form[@id='login']"));
WebElement input = formulario.findElement(By.xpath(".//input[@type='email']"));
}
- Utiliza índices específicos en lugar de funciones cuando la posición es conocida:
@Test
void indicesEspecificos() {
// Más eficiente para elementos en posiciones conocidas
WebElement segundoItem = driver.findElement(By.xpath("//ul/li[2]"));
// Reserva last() para casos donde la posición final es incierta
WebElement ultimoItem = driver.findElement(By.xpath("//ul/li[last()]"));
}
- Combina XPath con otros localizadores para maximizar la eficiencia:
@Test
void combinacionLocalizadores() {
// Localiza el contenedor por ID (más rápido)
WebElement contenedor = driver.findElement(By.id("productos"));
// Utiliza XPath relativo dentro del contenedor
WebElement producto = contenedor.findElement(
By.xpath(".//div[@data-price > 100]/button[contains(text(), 'Comprar')]")
);
}
Estas técnicas avanzadas de XPath proporcionan un arsenal completo para abordar los desafíos más complejos de localización de elementos en aplicaciones web modernas. La combinación estratégica de ejes, operadores lógicos y funciones de posición permite crear selectores robustos y mantenibles que se adaptan a las necesidades específicas de cada escenario de prueba.
Web Inspector
Si tenemos problemas a la hora de crear un xpath, podemos utilizar herramientas como Web Inspector de IntelliJ IDEA ayudan a validar la sintaxis xpath contra interfaces de usuario concretas>
Incluso la propia terminal del navegador permite el uso de selectores xpath y es capaz de indicarnos cuántos elementos ha detectado para nuestra sintaxis xpath.
Aprendizajes de esta lección de Selenium
- Comprender la diferencia entre XPath absoluto y relativo y su impacto en la robustez de las pruebas.
- Aprender a navegar por el DOM utilizando barras inclinadas y ejes XPath para seleccionar nodos específicos.
- Utilizar funciones y operadores lógicos para construir expresiones XPath complejas y precisas.
- Aplicar técnicas avanzadas como funciones de posición y XPath dinámico para adaptarse a estructuras DOM complejas.
- Conocer buenas prácticas y estrategias de optimización para mejorar el rendimiento en la localización de elementos con XPath.
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