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 PlusSelectores CSS básicos
Los selectores CSS representan una de las formas más eficientes y legibles de localizar elementos en el DOM durante la automatización de pruebas web. Selenium WebDriver implementa el método By.cssSelector()
que permite utilizar la misma sintaxis CSS que emplean los navegadores para aplicar estilos, pero adaptada para la localización de elementos.
La ventaja principal de los selectores CSS radica en su naturaleza intuitiva para desarrolladores web y su excelente rendimiento de ejecución. Al utilizar la misma sintaxis que CSS, resulta familiar para quienes han trabajado con hojas de estilo, facilitando la curva de aprendizaje.
Selectores fundamentales
Los selectores básicos constituyen la base de cualquier estrategia de localización CSS. Cada tipo de selector se enfoca en diferentes atributos del elemento HTML.
Selector por ID
El selector por ID utiliza el símbolo #
seguido del valor del atributo id
del elemento. Este selector es altamente específico y debería localizar un único elemento, ya que los IDs deben ser únicos en el DOM.
@Test
void testSelectorPorId() {
WebElement elemento = driver.findElement(By.cssSelector("#usuario"));
elemento.sendKeys("admin@ejemplo.com");
}
Selector por clase
El selector de clase emplea el símbolo .
seguido del nombre de la clase CSS. Es importante recordar que un elemento puede tener múltiples clases, y este selector localizará cualquier elemento que contenga la clase especificada.
@Test
void testSelectorPorClase() {
List<WebElement> botones = driver.findElements(By.cssSelector(".btn-primary"));
botones.forEach(WebElement::click);
}
Selector por elemento
Este selector utiliza directamente el nombre de la etiqueta HTML sin ningún símbolo adicional. Resulta útil cuando necesitamos localizar todos los elementos de un tipo específico.
@Test
void testSelectorPorElemento() {
List<WebElement> enlaces = driver.findElements(By.cssSelector("a"));
long enlacesVisibles = enlaces.stream()
.filter(WebElement::isDisplayed)
.count();
}
Selectores de atributo
Los selectores de atributo permiten localizar elementos basándose en la presencia o valor específico de sus atributos HTML. Proporcionan una flexibilidad considerable cuando los selectores básicos no son suficientes.
Selector por presencia de atributo
Localiza elementos que poseen un atributo específico, independientemente de su valor:
@Test
void testSelectorPorAtributo() {
List<WebElement> camposRequeridos = driver.findElements(By.cssSelector("[required]"));
assertThat(camposRequeridos).isNotEmpty();
}
Selector por valor exacto de atributo
Busca elementos cuyo atributo coincida exactamente con el valor especificado:
@Test
void testSelectorPorValorAtributo() {
WebElement campoEmail = driver.findElement(By.cssSelector("[type='email']"));
campoEmail.sendKeys("usuario@dominio.com");
}
Combinadores básicos
Los combinadores CSS permiten crear selectores más específicos estableciendo relaciones entre elementos en la estructura del DOM. Estos combinadores son fundamentales para localizar elementos en contextos específicos.
Combinador descendiente (espacio)
Un espacio entre selectores indica una relación descendiente, donde el segundo elemento debe estar contenido dentro del primero, sin importar el nivel de anidamiento:
@Test
void testCombinadorDescendiente() {
WebElement boton = driver.findElement(By.cssSelector("div.formulario button"));
boton.click();
}
Combinador hijo directo (>)
El símbolo >
especifica que el segundo elemento debe ser hijo directo del primero, es decir, no puede haber elementos intermedios:
@Test
void testCombinadorHijoDirecto() {
List<WebElement> itemsMenu = driver.findElements(By.cssSelector("nav > ul > li"));
itemsMenu.get(0).click();
}
Combinador hermano adyacente (+)
El símbolo +
localiza el elemento inmediatamente siguiente que sea hermano del elemento de referencia:
@Test
void testCombinadorHermanoAdyacente() {
WebElement etiquetaSiguiente = driver.findElement(By.cssSelector("input[type='checkbox'] + label"));
etiquetaSiguiente.click();
}
Combinador hermanos generales (~)
El símbolo ~
selecciona todos los elementos hermanos que siguen al elemento de referencia, no necesariamente de forma inmediata:
@Test
void testCombinadorHermanosGenerales() {
List<WebElement> camposSiguientes = driver.findElements(By.cssSelector("h2 ~ input"));
camposSiguientes.forEach(campo -> campo.clear());
}
Combinación de selectores
La combinación de múltiples selectores permite crear expresiones más precisas y específicas. Esta técnica resulta especialmente útil cuando trabajamos con páginas complejas donde un solo selector podría ser ambiguo.
@Test
void testSelectoresCombinados() {
// Combinar clase y atributo
WebElement botonEnviar = driver.findElement(By.cssSelector("button.btn-success[type='submit']"));
// Combinar ID y descendiente
WebElement campoNombre = driver.findElement(By.cssSelector("#formulario-registro input[name='nombre']"));
// Múltiples clases
WebElement alerta = driver.findElement(By.cssSelector(".alert.alert-danger"));
}
La sintaxis CSS ofrece una flexibilidad considerable para adaptar los selectores a las necesidades específicas de cada caso de prueba. La clave está en encontrar el equilibrio entre especificidad y mantenibilidad, creando selectores que sean lo suficientemente precisos para localizar el elemento correcto, pero no tan específicos que se rompan fácilmente ante cambios menores en la estructura del DOM.
Selectores CSS avanzados
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
Los selectores CSS avanzados amplían significativamente las capacidades de localización, permitiendo crear estrategias más sofisticadas para elementos complejos o dinámicos. Estos selectores resultan especialmente valiosos cuando trabajamos con aplicaciones web modernas que generan contenido dinámico o estructuras DOM complejas.
La potencia de los selectores avanzados reside en su capacidad para adaptarse a patrones específicos del DOM, proporcionando alternativas robustas cuando los selectores básicos no ofrecen la precisión necesaria.
Pseudo-clases estructurales
Las pseudo-clases estructurales permiten seleccionar elementos basándose en su posición relativa dentro de su contenedor padre. Estas pseudo-clases son fundamentales para localizar elementos en listas, tablas o cualquier estructura repetitiva.
Selector :nth-child()
La pseudo-clase :nth-child()
localiza elementos según su posición específica entre sus hermanos. Acepta números, palabras clave o fórmulas matemáticas:
@Test
void testNthChild() {
// Seleccionar el tercer elemento de una lista
WebElement tercerItem = driver.findElement(By.cssSelector("ul li:nth-child(3)"));
// Seleccionar elementos pares usando fórmula
List<WebElement> filasPares = driver.findElements(By.cssSelector("table tr:nth-child(even)"));
// Seleccionar cada tercer elemento usando fórmula
List<WebElement> cadaTercero = driver.findElements(By.cssSelector(".producto:nth-child(3n)"));
}
Selectores :first-child y :last-child
Estas pseudo-clases localizan respectivamente el primer y último elemento hijo dentro de su contenedor:
@Test
void testFirstLastChild() {
WebElement primerElemento = driver.findElement(By.cssSelector(".menu li:first-child"));
WebElement ultimoElemento = driver.findElement(By.cssSelector(".menu li:last-child"));
// Combinar con otros selectores para mayor especificidad
WebElement primerBoton = driver.findElement(By.cssSelector("form button:first-child"));
}
Selector :nth-of-type()
Esta pseudo-clase selecciona elementos según su posición entre elementos del mismo tipo:
@Test
void testNthOfType() {
// Seleccionar el segundo párrafo dentro de un div
WebElement segundoParrafo = driver.findElement(By.cssSelector("div p:nth-of-type(2)"));
// Seleccionar el último input de tipo text
WebElement ultimoInput = driver.findElement(By.cssSelector("input[type='text']:last-of-type"));
}
Pseudo-clases de estado
Las pseudo-clases de estado permiten localizar elementos basándose en su estado actual en la interfaz de usuario. Estas pseudo-clases son especialmente útiles para validaciones y verificaciones dinámicas.
@Test
void testPseudoClasesEstado() {
// Localizar elementos habilitados
List<WebElement> camposHabilitados = driver.findElements(By.cssSelector("input:enabled"));
// Localizar elementos deshabilitados
List<WebElement> camposDeshabilitados = driver.findElements(By.cssSelector("input:disabled"));
// Localizar checkboxes marcados
List<WebElement> checkboxesMarcados = driver.findElements(By.cssSelector("input[type='checkbox']:checked"));
}
Selectores de atributo avanzados
Los selectores de atributo avanzados ofrecen capacidades de coincidencia de subcadenas, permitiendo localizar elements basándose en patrones específicos dentro de los valores de sus atributos.
Selector de contiene subcadena (*=)
El operador *=
localiza elementos cuyo atributo contiene la subcadena especificada en cualquier posición:
@Test
void testAtributoContiene() {
// Localizar elementos cuya clase contiene "button"
List<WebElement> botones = driver.findElements(By.cssSelector("[class*='button']"));
// Localizar inputs cuyo name contiene "email"
WebElement campoEmail = driver.findElement(By.cssSelector("input[name*='email']"));
}
Selector comienza con (^=)
El operador ^=
selecciona elementos cuyo atributo comienza con la cadena especificada:
@Test
void testAtributoComienza() {
// Localizar elementos cuyo ID comienza con "form"
List<WebElement> formularios = driver.findElements(By.cssSelector("[id^='form']"));
// Localizar enlaces que comienzan con "https"
List<WebElement> enlacesSegures = driver.findElements(By.cssSelector("a[href^='https']"));
}
Selector termina con ($=)
El operador $=
localiza elementos cuyo atributo termina con la cadena especificada:
@Test
void testAtributoTermina() {
// Localizar elementos cuya clase termina con "error"
List<WebElement> camposError = driver.findElements(By.cssSelector("[class$='error']"));
// Localizar imágenes PNG
List<WebElement> imagenesPng = driver.findElements(By.cssSelector("img[src$='.png']"));
}
Selectores de negación
El selector de negación :not()
permite excluir elementos que coincidan con el selector especificado dentro de los paréntesis:
@Test
void testSelectorNegacion() {
// Localizar todos los inputs excepto los de tipo hidden
List<WebElement> inputsVisibles = driver.findElements(By.cssSelector("input:not([type='hidden'])"));
// Localizar botones que no tengan la clase "disabled"
List<WebElement> botonesActivos = driver.findElements(By.cssSelector("button:not(.disabled)"));
// Localizar divs que no contengan la clase "oculto"
List<WebElement> divsVisibles = driver.findElements(By.cssSelector("div:not([class*='oculto'])"));
}
Selectores avanzados combinados
La combinación de selectores avanzados permite crear expresiones altamente específicas para escenarios complejos:
@Test
void testSelectoresAvanzadosCombinados() {
// Localizar el primer botón habilitado dentro de un formulario específico
WebElement primerBotonActivo = driver.findElement(
By.cssSelector("#formulario-principal button:enabled:first-of-type")
);
// Localizar filas pares de una tabla que no estén marcadas como eliminadas
List<WebElement> filasValidasPares = driver.findElements(
By.cssSelector("table tr:nth-child(even):not([class*='deleted'])")
);
// Localizar elementos con atributos específicos y estado
WebElement elementoComplejo = driver.findElement(
By.cssSelector("input[name^='usuario'][type='text']:enabled:not([readonly])")
);
}
Técnicas de optimización
Para maximizar la eficiencia de los selectores CSS avanzados, es recomendable seguir ciertas prácticas:
@Test
void testOptimizacionSelectores() {
// Preferir selectores específicos sobre búsquedas amplias
WebElement elemento = driver.findElement(
By.cssSelector("#contenedor .lista-productos li:nth-child(5)")
);
// Utilizar atributos únicos cuando estén disponibles
WebElement botonEspecifico = driver.findElement(
By.cssSelector("button[data-testid='submit-form']")
);
// Combinar múltiples criterios para mayor precisión
List<WebElement> elementosFiltrados = driver.findElements(
By.cssSelector("div.producto:not(.agotado) button[type='button']:enabled")
);
}
Los selectores CSS avanzados proporcionan una flexibilidad excepcional para abordar los desafíos más complejos de localización de elementos. Su dominio resulta esencial para desarrollar suites de pruebas robustas que puedan adaptarse a interfaces de usuario dinámicas y estructuras DOM complejas, manteniendo al mismo tiempo un rendimiento óptimo en la ejecución de las pruebas.
Consideraciones de rendimiento XPath vs CSS
El rendimiento de localización constituye un factor crítico en la ejecución de suites de pruebas automatizadas, especialmente cuando se manejan aplicaciones web complejas con miles de elementos. La elección entre selectores CSS y XPath puede impactar significativamente en los tiempos de ejecución y la eficiencia general de las pruebas.
Los navegadores modernos están optimizados nativamente para procesar selectores CSS, ya que forman parte fundamental del motor de renderizado. Esta optimización inherente convierte a los selectores CSS en la opción preferida para la mayoría de escenarios de localización de elementos.
Ventajas de rendimiento de CSS
Los selectores CSS aprovechan el motor de consultas CSS nativo del navegador, que ha sido optimizado durante décadas para aplicar estilos de manera eficiente. Esta optimización se traduce en tiempos de búsqueda considerablemente menores.
@Test
void testComparacionRendimientoBasico() {
long inicioCSS = System.nanoTime();
WebElement elementoCSS = driver.findElement(By.cssSelector(".producto[data-id='123'] button"));
long tiempoCSS = System.nanoTime() - inicioCSS;
long inicioXPath = System.nanoTime();
WebElement elementoXPath = driver.findElement(By.xpath("//div[@class='producto'][@data-id='123']//button"));
long tiempoXPath = System.nanoTime() - inicioXPath;
System.out.printf("CSS: %d ns, XPath: %d ns%n", tiempoCSS, tiempoXPath);
}
Factores que afectan al rendimiento
La complejidad del DOM influye directamente en el rendimiento de ambos tipos de selectores. Sin embargo, el impacto varía según la estrategia de localización empleada.
Profundidad del DOM
Los selectores CSS mantienen un rendimiento más consistente incluso en estructuras DOM profundamente anidadas:
@Test
void testRendimientoProfundidadDOM() {
// CSS mantiene eficiencia en estructuras profundas
WebElement elementoProfundoCSS = driver.findElement(
By.cssSelector("#contenedor .seccion .subseccion .elemento-objetivo")
);
// XPath puede degradarse con mayor profundidad
WebElement elementoProfundoXPath = driver.findElement(
By.xpath("//div[@id='contenedor']//div[@class='seccion']//div[@class='subseccion']//div[@class='elemento-objetivo']")
);
}
Número de elementos coincidentes
Cuando existen múltiples elementos que coinciden parcialmente con el selector, CSS suele filtrar más eficientemente:
@Test
void testRendimientoMultiplesElementos() {
// CSS optimiza búsquedas en listas grandes
List<WebElement> productosCSS = driver.findElements(
By.cssSelector(".producto:nth-child(even) .precio")
);
// XPath puede ser menos eficiente con predicados complejos
List<WebElement> productosXPath = driver.findElements(
By.xpath("//div[@class='producto'][position() mod 2 = 0]//span[@class='precio']")
);
}
Casos donde XPath mantiene competitividad
Aunque CSS generalmente supera a XPath en rendimiento, existen escenarios específicos donde XPath puede resultar más eficiente o necesario.
Navegación hacia elementos padre
XPath permite navegar hacia elementos padre de manera directa, mientras que CSS requiere estrategias alternativas:
@Test
void testNavegacionElementoPadre() {
// XPath: navegación directa al padre
WebElement contenedorPadre = driver.findElement(
By.xpath("//button[text()='Eliminar']/parent::div")
);
// CSS: requiere localizar el padre desde una perspectiva diferente
WebElement botonEliminar = driver.findElement(By.cssSelector("button"));
WebElement contenedorAlternativo = (WebElement) ((JavascriptExecutor) driver)
.executeScript("return arguments[0].parentElement;", botonEliminar);
}
Búsquedas por contenido de texto
XPath ofrece capacidades nativas para buscar por contenido textual, mientras que CSS requiere enfoques alternativos:
@Test
void testBusquedaPorTexto() {
// XPath: búsqueda directa por texto
WebElement enlacePorTexto = driver.findElement(
By.xpath("//a[contains(text(), 'Términos de servicio')]")
);
// CSS: requiere localizar y filtrar posteriormente
List<WebElement> todosLosEnlaces = driver.findElements(By.cssSelector("a"));
WebElement enlaceEncontrado = todosLosEnlaces.stream()
.filter(enlace -> enlace.getText().contains("Términos de servicio"))
.findFirst()
.orElseThrow();
}
Optimización de selectores para rendimiento
La estructura del selector impacta significativamente en el rendimiento independientemente del tipo elegido.
Principios de optimización CSS
@Test
void testOptimizacionCSS() {
// Preferir selectores específicos y únicos
WebElement optimizado = driver.findElement(By.cssSelector("#formulario-login input[name='usuario']"));
// Evitar selectores excesivamente genéricos
// Menos eficiente: driver.findElement(By.cssSelector("div div div input"));
// Utilizar atributos data-testid cuando estén disponibles
WebElement conTestId = driver.findElement(By.cssSelector("[data-testid='login-button']"));
}
Técnicas de medición de rendimiento
Para evaluar objetivamente el rendimiento de diferentes estrategias de localización:
@Test
void testMedicionRendimiento() {
int iteraciones = 100;
// Medir CSS
long totalCSS = IntStream.range(0, iteraciones)
.mapToLong(i -> {
long inicio = System.nanoTime();
driver.findElement(By.cssSelector(".producto[data-id='123']"));
return System.nanoTime() - inicio;
})
.sum();
// Medir XPath
long totalXPath = IntStream.range(0, iteraciones)
.mapToLong(i -> {
long inicio = System.nanoTime();
driver.findElement(By.xpath("//div[@class='producto'][@data-id='123']"));
return System.nanoTime() - inicio;
})
.sum();
double promedioCSS = totalCSS / (double) iteraciones;
double promedioXPath = totalXPath / (double) iteraciones;
System.out.printf("Promedio CSS: %.2f ns, Promedio XPath: %.2f ns%n",
promedioCSS, promedioXPath);
}
Recomendaciones estratégicas
Para maximizar el rendimiento en proyectos de automatización de pruebas:
- Priorizar CSS como estrategia principal de localización, especialmente para elementos con atributos identificadores únicos
- Reservar XPath para casos específicos que requieran navegación compleja o búsquedas por contenido textual
- Implementar atributos data-testid en el desarrollo de la aplicación para facilitar selectores CSS optimizados
- Medir regularmente el rendimiento de selectores críticos para identificar posibles degradaciones
@Test
void testEstrategiaOptima() {
// Estrategia recomendada: CSS con atributos específicos
WebElement elementoOptimo = driver.findElement(
By.cssSelector("[data-testid='submit-order-button']")
);
// Alternativa CSS para casos complejos
WebElement alternativaCSS = driver.findElement(
By.cssSelector("#order-form .actions button:nth-of-type(2)")
);
// XPath solo cuando sea necesario
WebElement xpathNecesario = driver.findElement(
By.xpath("//button[preceding-sibling::input[@type='checkbox' and @checked]]")
);
}
La elección informada entre CSS y XPath, basada en las características específicas de cada caso de uso y mediciones de rendimiento objetivas, constituye una competencia fundamental para desarrollar suites de pruebas eficientes y mantenibles. Los selectores CSS deben considerarse la opción predeterminada, reservando XPath para aquellos escenarios donde sus capacidades únicas justifiquen el potencial impacto en el rendimiento.
Aprendizajes de esta lección de Selenium
- Comprender la sintaxis y uso de selectores CSS básicos para localizar elementos en el DOM.
- Aprender a utilizar selectores de atributo y combinadores para crear selectores más específicos.
- Dominar selectores CSS avanzados como pseudo-clases estructurales, de estado y selectores de negación.
- Aplicar técnicas de optimización para mejorar el rendimiento de los selectores CSS en pruebas automatizadas.
- Comparar el rendimiento y casos de uso entre selectores CSS y XPath para elegir la mejor estrategia de localización.
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