Sesión 5 de mi lab de Selenium + Java: Localizadores en Selenium
DOM, selector, locator y By: qué es cada cosa y cómo elegir el mejor. Jerarquía práctica de id a XPath. Primer test de login real en demo.serenity.is
Inicio
"Abrir un sitio es fácil. Interactuar con él de forma mantenible es otra cosa."
En las sesiones anteriores armé el wiring básico del proyecto:
configuración, driver manager, primer test que abre el sitio.
En esta sesión doy un paso más importante:
interactuar con la interfaz de forma consciente para testear una funcionalidad real, en este caso el login.
El objetivo es que el test “funcione” y además conversar acerca de:
- Localizar los elementos del sitio web
El primer flujo real: login
Realicé cambios en PrimerTest.java
Agregué líneas para poder loguearse en demo.serenity.is. Para esto tuve que usar localizadores de los elementos web del login:
- input de usuario
- input de password
- y botón de iniciar sesión.
En este test probé el uso de esperas. Practiqué cómo se usan en el código y cuál es su resultado en la prueba.

Código completo:
package com.cesar.qa.tests;
import com.cesar.qa.config.ConfigReader; // - importar ConfigReader
import com.cesar.qa.config.DriverManager; // - importar DriverManager
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.testng.annotations.Test;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
public class PrimerTest {
@Test
public void abrirSerenityis() {
// 1) Inicializa el WebDriver según lo que diga config.properties
// - browser=chrome
// - headless=true/false
// - window.maximize=true/false
// - timeouts
// Nota: Esto evita tener "new ChromeDriver()" en cada test.
DriverManager.initDriver();
// 2) Obtiene la instancia del driver creada por DriverManager
// (Si todavía no existe, la crea automáticamente).
WebDriver driver = DriverManager.getDriver();
// 3) Lee la URL base desde config.properties
// Ej: base.url=https://demo.serenity.is
String baseUrl = ConfigReader.getProperty("base.url");
// 4) Navega a la URL configurada
// (Esto reemplaza el hardcode: driver.get("https://demo.serenity.is/..."))
driver.get(baseUrl);
// 3) Localiza inputs
By usuarioInput = By.id("LoginPanel0_Username");
By passwordInput = By.id("LoginPanel0_Password");
By loginButton = By.id ("LoginPanel0_LoginButton");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// 4) Limpia e ingresa usuario
WebElement usuario = wait.until(ExpectedConditions.visibilityOfElementLocated(usuarioInput));
usuario.clear();
usuario.sendKeys("admin");
// 5) Limpia e ingresa password
WebElement password = wait.until(ExpectedConditions.visibilityOfElementLocated(passwordInput));
password.clear();
password.sendKeys("serenity");
// 6) Click en iniciar sesión
wait.until(ExpectedConditions.elementToBeClickable(loginButton)).click();
// (opcional) pequeña validación visual / pausa
System.out.println("Login ejecutado");
// 5) Validación / evidencia simple: imprimir el título de la página
// En esta etapa, el objetivo es confirmar que todo el wiring funciona.
String titulo = driver.getTitle();
System.out.println("Título de la página: " + titulo);
// 6) Cierra el navegador y limpia el driver para la próxima ejecución
// (Más adelante esto se moverá a un BaseTest con @AfterMethod)
// DriverManager.quitDriver();
System.out.println("Test ejecutado correctamente");
}
}
Resultado de la ejecución

todo ok 👍
El test abre login y limpia las credenciales que vienen por defecto en los campos de usuario y password y luego hace click en iniciar sesión.

y abre el dashboard

Este es el primer flujo que automatizo en Serenity Demo.
A continuación hablo acerca de los localizadores.
Charlo acerca de lo que es más usado y porqué, de acuerdo a lo que investigué.
DOM, selector, locator y By: qué es cada cosa (sin confusión)
Cuando empezás con Selenium aparecen palabras que parecen sinónimos, pero no lo son.
Si no las entendés bien, terminas escribiendo tests “a prueba y error”.
Vamos por partes.
DOM: lo que Selenium realmente ve
DOM (Document Object Model) es la representación en memoria que el navegador construye de una página web.

No es el HTML en texto.
Es un árbol de objetos que el navegador construye para poder:
- mostrar la página
- aplicar CSS
- ejecutar JavaScript
- y permitir que herramientas como Selenium encuentren elementos
HTML vs DOM (clave)
HTML (archivo)
<input id="username" type="text">Es solo texto.
DOM (en memoria)
Document
└── html
└── body
└── input
├── id = "username"
└── type = "text"👉 El navegador parsea el HTML y lo convierte en este árbol.
Por qué se dice “árbol DOM”
Porque:
- cada elemento es un nodo
- tiene padres, hijos y hermanos
- hay una raíz (
document)
Ejemplo:
<form>
<input />
<button>Login</button>
</form>Relaciones:
form→ padreinputybutton→ hijosinput↔button→ hermanos
Selenium NO busca en el HTML
Esto es muy importante:
Selenium no lee el archivo HTML
Selenium interactúa con el DOM vivo
Por eso:
- elementos que aparecen con JS → Selenium sí los ve
- elementos ocultos → existen en el DOM
- cambios dinámicos → el DOM cambia
Selectores y DOM
Un selector siempre apunta al DOM.
Ejemplos:
➡ busca en el DOM un nodo con id="username"
By.id("username")➡ navega el árbol DOM:form → hijo input
By.cssSelector("form input")➡ busca un nodo button cuyo texto sea “Login”
By.xpath("//button[text()='Login']")DOM ≠ lo que ves en pantalla
Hay cosas que:
- existen en el DOM
- pero no son visibles
Ejemplos:
display: nonevisibility: hidden- elementos fuera del viewport
- modales ocultos
👉 Selenium puede encontrarlos, pero no siempre interactuar con ellos.
Definición para QA (la buena)
El DOM es la estructura viva que Selenium inspecciona, recorre y manipula para automatizar una web.
Si entendés el DOM:
- elegís mejores locators
- evitás XPath frágiles
- entendés por qué fallan los waits
- dejás de “probar a ciegas”
Selector: cómo identificás un elemento en el DOM
Es la forma concreta de identificar un elemento en el DOM.
Ejemplos:
#login-buttoninput[type='email']//button[text()='Login']username
👉 Esto existe antes de Selenium (HTML / CSS / XPath).
Los selectores no son de Selenium.
Vienen de:
- CSS
- XPath
- HTML
Orden de prioridad para elegir selectores
1️⃣ id (si existe y es estable)
By.id("login-button")✔ Único
✔ Rápido
✔ Legible
✔ Muy estable
Regla:
Si hay id y no cambia → usalo sin pensar.2️⃣ data-* (ideal en apps modernas)
By.cssSelector("[data-testid='login-btn']")✔ Diseñados para testing
✔ No dependen del layout
✔ Ultra estables
👉 Si podés pedirlos al dev, pedilos.
3️⃣ CSS selector por atributos
By.cssSelector("input[type='email']")
By.cssSelector("button[name='submit']")✔ Potente
✔ Más corto que XPath
✔ Bastante estable
4️⃣ CSS por jerarquía simple
By.cssSelector("form#loginForm button[type='submit']")✔ Legible
⚠ Frágil si cambia la estructura
Usar solo si no hay algo mejor.
5️⃣ XPath simple (cuando CSS no alcanza)
By.xpath("//button[text()='Login']")✔ Accede al texto
✔ Útil para validaciones
⚠ Frágil si cambia idioma o copy
6️⃣ XPath complejo / absoluto (último recurso)
By.xpath("/html/body/div[2]/form/div[3]/button")❌ Muy frágil
❌ Difícil de leer
❌ Se rompe con cualquier cambio
👉 Evitar siempre que sea posible.
Selectores a evitar (salvo emergencia)
By.classNamecon clases de framework (css-123abc)- XPath con índices (
div[3]/span[2]) - Selectores basados en estilos (
color,position) - Textos cambiantes (“Aceptar”, “Confirmar”, etc.)
Regla de oro (la que realmente importa)
Cuanto más cerca estés del negocio
y más lejos del layout,
mejor es el selector.
Jerarquía resumida
1. id2. data-* (data-testid, data-qa, etc.)3. CSS por atributo4. CSS por jerarquía simple5. XPath simple6. XPath complejo (evitar)
Elegir un selector no es una decisión técnica menor.
Es una decisión de mantenibilidad.
Un buen selector apunta al significado del elemento,
no a cómo está dibujado en pantalla.
Si mañana cambia el layout y tu test se rompe,
el selector era el problema.
Locator: el selector entendido por Selenium
Un locator es el selector envuelto en algo que Selenium entiende.
Es la abstracción que usa la herramienta de automatización para localizar un elemento, usando un selector.
En Selenium Java, el locator es:
By.id("login-button")👉 El locator incluye:
- el tipo de selector (id, css, xpath…)
- el valor del selector
En Selenium se usa además un “envoltorio”, la clase By.
Ejemplo:
By loginButton = By.id("login-button");Acá:
"login-button"→ es el selectorBy.id(...)→ es la estrategia- todo junto → es el locator
El locator es lo que Selenium usa para localizar un elemento en el DOM.
Relación exacta entre Locator y Selector
Selector = “cómo identificar”
Locator = “cómo Selenium lo representa”
En Selenium:
By.cssSelector("input[type='email']")cssSelector→ tipo de selector"input[type='email']"→ selector- todo junto → locator
Ejemplo comparativo
Selector (conceptual / DOM)
#submit-btnLocator (Selenium Java)
By submitButton = By.cssSelector("#submit-btn");En el día a día como QA
En conversaciones reales vas a escuchar:
“Ese locator es frágil”
“Cambió el selector”
“Arreglé los locators del login”
Y está bien. Nadie te va a corregir eso.
Regla práctica (la que importa)
| Contexto | Palabra correcta |
|---|---|
| HTML / CSS / XPath | Selector |
| Selenium / Playwright / Cypress | Locator |
| Charla informal | Son sinónimos |
| Diseño de framework | Locator |
Frase para quedarte
El selector identifica.
El locator encapsula esa identificación para la herramienta.
By: la sintaxis de Selenium (no el selector)
By es parte de la sintaxis de Selenium para expresar selectores, no es el selector en sí.
Dicho simple:
El selector es el criterio (id, css, xpath, name, etc.)Byes el wrapper que Selenium usa para entenderlo
Qué es realmente By en Selenium (Java)
By es una clase de Selenium que representa una estrategia de búsqueda de elementos.
Cuando escribís:
By.id("username")lo que estás diciendo es:
“Buscá un elemento por ID cuyo valor sea username”.
Sintaxis general
Todos los selectores en Selenium Java siguen esta forma:
By.<tipoDeSelector>(valor)Ejemplos:
By.id("email")
By.name("password")
By.className("btn-primary")
By.cssSelector("button[type='submit']")
By.xpath("//input[@type='text']")👉 By es obligatorio en Selenium Java para localizar elementos.
Importante: By no es Selenium “sucio”
Mucha gente piensa:
“Quiero evitar By”
Pero el objetivo no es evitarlo, sino aislarlo.
Ejemplo malo (ruido en el test):
driver.findElement(By.id("username")).sendKeys("admin");
driver.findElement(By.id("password")).sendKeys("1234");
driver.findElement(By.id("login")).click();Ejemplo bueno (By aislado):
// Locators
private By usernameInput = By.id("username");
private By passwordInput = By.id("password");
private By loginButton = By.id("login");// Uso
type(usernameInput, "admin");
type(passwordInput, "1234");
click(loginButton);👉 El test lee negocio, no sintaxis.
Resumen mental
- ❌
Byno es el selector - ✅
Byes la forma que Selenium usa para interpretar el selector - ✅ El selector real es:
id,css,xpath, etc. - 🎯 Buen diseño = selectores aislados, tests limpios
Cómo se conectan todos los conceptos
La cadena completa es esta:
DOM → selector → locator (By) → Selenium
Ejemplo mental:
“En el DOM hay un botón.
Lo identifico con un selector CSS.
Selenium lo envuelve en unBy.
Y recién ahí puede interactuar.”
Por qué esto importa al diseñar un framework
El objetivo no es evitar By, sino aislarlo.
Mal diseño (ruido en el test):
driver.findElement(By.id("login")).click();Buen diseño (intención clara):
private By loginButton = By.id("login");
click(loginButton);Los locators no son parte del negocio, son parte de la infraestructura del test.
Por eso necesitan vivir en un lugar donde puedan cambiar sin romper la lógica de las pruebas.
Estos necesitaran cambios de acuerdo a nuevas versiones de la web, que llegan con cambios en la UI.
Por otro lado, en otra parte, hay que tener los tests, las pruebas que necesita el negocio.
Separadas, aisladas y que no contengan código que distraiga o de problemas.
Lo fundamental es el negocio, hacer las pruebas que importan.
👉 El test habla de negocio.
👉 La sintaxis queda escondida.
Para cerrar, volver a indicar lo importante a considerar en la elección del selector y locator:
Cuanto más cerca estés del negocio
y más lejos del layout,
mejor es el selector.
En la siguiente sesión hablare acerca de:
- El tiempo para encontrar los elementos de la web y simular escribir, hacer click en ellos, o sea el tiempo en las pruebas
- Y el porqué se busca estructurar el código, aislar código que se repite mucho y dejar código de pruebas de negocio lo más limpio posible
🔗 Todo el código de esta serie está en: github.com/cesarbeassuarez/qa-automation-lab
📂 selenium-java
—
Temas conectados:
Sesión 3 de este lab y Sesión 4 de este lab de Selenium con java.