Tools: Selenium 101: Primeros pasos en la automatización de pruebas - Complete Guide

Tools: Selenium 101: Primeros pasos en la automatización de pruebas - Complete Guide

1. ¿Por qué escribo sobre Selenium? De la frustración a la automatización

2. Introducción e Historia

3. Características Principales

4. Componentes del Ecosistema

5. Drivers y Soporte

6. Lenguajes Soportados

7. Instalación y Configuración

8. Beneficios de Automatizar

9. Conceptos Clave y Código

10. Puntos Críticos de Aprendizaje

11. Documentación y Comunidad

Tips para los que vamos iniciando Una mini guía para dar el salto al mundo de la automatización. Desde los conceptos fundamentales hasta ejemplos de código. Contenido del artículo Este artículo nace de una doble motivación: una reciente asignación de investigación y, sobre todo, mi experiencia personal "en las trincheras" de la automatización. Mi historia con Selenium comenzó en tercer semestre de la universidad. Cada fin de ciclo, nos enfrentábamos al tedioso ritual de llenar múltiples encuestas académicas en el portal institucional. Después de varios semestres dedicando 15 minutos de mi vida a clics repetitivos, llegué a un punto de quiebre. Decidí que, en lugar de regalarle esos minutos al sistema una vez más, dedicaría una noche entera a entender cómo obligar al navegador a hacerlo por mí. Armado con tutoriales de YouTube y mucha curiosidad, logré desarrollar una primera solución funcional. Al mostrarle el resultado a una de mis maestras, su reacción fue una mezcla de sorpresa y felicitación; le causó gracia que, fiel a la filosofía de un desarrollador, prefiriera: "Invertir horas automatizando una tarea, en lugar de perder 15 minutos haciéndola manual" Ese pequeño proyecto fue mi puerta de entrada a un mundo mucho más grande. Poco después, conocí a otra profesora que trabajaba como Tester en una consultora de renombre. Ella me abrió los ojos hacia el ecosistema profesional del testing y la enorme variedad de herramientas que existen. Un par de semestres más tarde, con más conocimientos bajo el brazo, desarrollé la versión 2.0 de aquel script. Esta vez no solo fue funcional, sino que lo compartí en GitHub y se convirtió en un éxito entre mis compañeros. ¡Fue gratificante saber que les había ahorrado esos 15 minutos de tedio a tantas personas! Desde entonces, Selenium me ha acompañado en mi camino profesional. Si bien no me considero un experto absoluto, comparto este conocimiento con la intención de que tú también puedas transformar tareas repetitivas en procesos eficientes. Selenium es, sin lugar a dudas, el framework de automatización de pruebas web más utilizado en la industria del software. Pero, ¿cómo llegó a convertirse en el estándar? Su historia es tan interesante como su funcionamiento. 2004: Nacimiento de Selenium Core. Jason Huggins, ingeniero de ThoughtWorks, crea una herramienta interna para automatizar pruebas de la aplicación de gestión de tiempo de su empresa. La llamó "JavaScript Test Runner" y luego la renombró Selenium. 2006: Selenium IDE y Selenium RC. Paul Hammant desarrolla Selenium Remote Control (RC), permitiendo ejecutar pruebas en múltiples lenguajes. Simon Stewart comienza a trabajar en WebDriver como proyecto en Google. 2008: Unificación histórica. Los equipos de Selenium RC y WebDriver se fusionan. Nace Selenium 2 con WebDriver como componente central. Este fue un punto de inflexión definitivo para la herramienta. 2016: Selenium 3. Se lanza como una gran actualización que elimina el antiguo Selenium RC y consolida WebDriver como el núcleo, adoptando además el protocolo W3C WebDriver. 2021 - hoy: Selenium 4. La versión actual trae soporte nativo al protocolo W3C, mejor integración con Chrome DevTools Protocol (CDP), soporte para ventanas relativas, y una API más limpia e intuitiva. Esta es la versión que aprenderás en esta guía. Open Source y Gratuito

Sin costos de licencia. La comunidad global lo mantiene activamente bajo licencia Apache 2.0. Multi-navegadorCompatible con Chrome, Firefox, Safari, Edge y Opera. Prueba en todos los entornos de tus usuarios. Multi-lenguajeEscribe tus pruebas en Java, Python, C#, JavaScript, Ruby o Kotlin Integración con CI/CDSe integra con Jenkins, GitHub Actions, GitLab CI, Docker y frameworks como TestNG o JUnit. Ejecución en GridDistribuye pruebas en múltiples máquinas simultáneamente para reducir tiempo de ejecución. Protocolo W3CSelenium 4 es 100% compatible con el estándar W3C WebDriver, garantizando estabilidad a largo plazo. Selenium no es una sola herramienta, sino un ecosistema compuesto por tres componentes principales. Conocerlos te ayudará a elegir la herramienta correcta para cada necesidad. Selenium WebDriverEs el componente central y el que utilizarás principalmente para escribir scripts de automatización. WebDriver provee una API que permite controlar el navegador de forma programática: hacer clics, escribir texto, navegar entre páginas, extraer información, etc. Se comunica directamente con el driver del navegador usando el protocolo W3C. Para principiantesCuando alguien dice "aprendo Selenium", en el 95% de los casos se refiere a aprender Selenium WebDriver. Es el núcleo de todo. Selenium IDEEs una extensión de navegador (disponible para Chrome y Firefox) que permite grabar y reproducir acciones en el navegador sin escribir código. Es una herramienta excelente para: Limitación importanteLos scripts grabados con IDE son frágiles ante cambios en la UI. Para proyectos reales de automatización, se usa WebDriver con código. Selenium GridPermite ejecutar pruebas en paralelo en múltiples máquinas y navegadores al mismo tiempo. Funciona con una arquitectura Hub-Node: el Hub es el servidor central que recibe las pruebas y las distribuye a los Nodes (máquinas con navegadores instalados). Ideal para grandes suites de prueba en entornos CI/CD. Selenium no controla el navegador directamente. Necesita un intermediario: el Browser Driver. Este driver traduce los comandos de WebDriver al lenguaje nativo del navegador. Selenium Manager (novedad en Selenium 4)A partir de Selenium 4.6+, el Selenium Manager descarga y configura automáticamente el driver correcto para tu versión de navegador. ¡Ya no necesitas gestionar drivers manualmente en la mayoría de los casos! Compatibilidad de Sistemas Operativos Una de las grandes ventajas de Selenium es que puedes usarlo con tu lenguaje de programación favorito. Actualmente soporta oficialmente: ¿Cuál elegir si eres principiante?Python es la recomendación más común por su sintaxis legible y curva de aprendizaje suave. Java es la mejor opción si tu empresa ya lo usa o si buscas más oportunidades laborales en QA Enterprise. Los ejemplos en esta guía usan Python. Vamos paso a paso. Para empezar con Selenium + Python necesitas instalar lo siguiente: Paso 1 — Instalar PythonDescarga Python 3.9 o superior desde python.org. Verifica la instalación en tu terminal: Paso 2 — Instalar SeleniumUsa pip, el gestor de paquetes de Python, para instalar la librería de Selenium: Paso 3 — Configurar tu IDERecomiendo VSCode (gratuito, ligero, muy cómodo y fácil de usar) o PyCharm Community Edition (de lo mas completo para trabajar con Python). Ambos tienen extensiones para Python con autocompletado y debugging. Paso 4 — Drivers (opcional con Selenium 4+)Selenium Manager gestiona los drivers automáticamente. Si necesitas control manual, instala webdriver-manager: Paso 5 — Tu primer script de verificación La automatización de pruebas no reemplaza al tester manual: lo potencia. Estos son los beneficios concretos que justifican la inversión: Localizadores (Locators)Para interactuar con un elemento web, primero debes encontrarlo. Selenium provee múltiples estrategias de localización: Jerarquía de preferencia de locatorsUsa en este orden: ID → Name → CSS Selector → XPath. El XPath absoluto (el que genera el inspector de Chrome copiando la ruta completa) es el más frágil; evítalo. Prefiere XPath relativos y descriptivos. Script de ejemplo completo — Login automatizado Manejo de Esperas (Waits) Este es el tema que más problemas causa a los principiantes. Los navegadores modernos cargan contenido de forma asíncrona (AJAX, SPA). Si Selenium intenta interactuar con un elemento antes de que esté listo, obtendrás un NoSuchElementException. La solución: waits. Evita time.sleep() — el antipatrón más comúntime.sleep(3) es una espera fija y ciega. Hace tus pruebas lentas en máquinas rápidas y falla en máquinas lentas. Siempre usa Explicit Wait en su lugar. Page Object Model (POM) El Page Object Model es el patrón de diseño más importante que aprenderás en automatización. La idea central es: cada página de la aplicación tiene una clase Python que representa sus elementos e interacciones. Los tests solo llaman a métodos de esas clases, no manipulan el driver directamente. test_login.py → LoginPage → WebDriverTests llaman métodos → Page Objects manejan locators → Driver controla el navegador ¿Por qué POM es importante?Sin POM, si el ID de un campo cambia en la UI, debes buscar y editar todos los tests que lo usan. Con POM, solo editas el locator en un lugar: la clase de la página. Esto es mantenibilidad real. El aprendizaje no termina con este artículo. Estos son los recursos más valiosos para continuar: selenium.dev/documentationDocumentación oficial. La fuente de verdad para APIs, guías y cambios por versión. The Internet (Heroku)the-internet.herokuapp.com — colección de escenarios de UI complejos para practicar: dropdowns, iframes, alerts, auth. r/QualityAssuranceComunidad activa en Reddit con discusiones sobre herramientas, carrera y mejores prácticas de QA Automation. Practice Test Automationpracticetestautomation.com — sitios de práctica diseñados específicamente para aprender Selenium. Stack Overflow — selenium+100,000 preguntas etiquetadas con [selenium]. Si tienes un error, probablemente ya fue resuelto aquí. Ministry of Testing

ministryoftesting.com — comunidad global de testers con artículos, cursos y una comunidad muy activa. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ bash — verificación python --version # Output esperado: Python 3.11.x -weight: 500;">pip --version # Output esperado: -weight: 500;">pip 23.x.x bash — verificación python --version # Output esperado: Python 3.11.x -weight: 500;">pip --version # Output esperado: -weight: 500;">pip 23.x.x bash — verificación python --version # Output esperado: Python 3.11.x -weight: 500;">pip --version # Output esperado: -weight: 500;">pip 23.x.x bash — instalación -weight: 500;">pip -weight: 500;">install selenium # Verifica la instalación: -weight: 500;">pip show selenium # Deberías ver: Name: selenium, Version: 4.x.x bash — instalación -weight: 500;">pip -weight: 500;">install selenium # Verifica la instalación: -weight: 500;">pip show selenium # Deberías ver: Name: selenium, Version: 4.x.x bash — instalación -weight: 500;">pip -weight: 500;">install selenium # Verifica la instalación: -weight: 500;">pip show selenium # Deberías ver: Name: selenium, Version: 4.x.x bash -weight: 500;">pip -weight: 500;">install webdriver-manager bash -weight: 500;">pip -weight: 500;">install webdriver-manager bash -weight: 500;">pip -weight: 500;">install webdriver-manager python — verificación_setup.py from selenium import webdriver driver = webdriver.Chrome() driver.get("https://www.selenium.dev") print(driver.title) # Imprime el título de la página driver.quit() # Si ves el título en consola, ¡tu setup funciona! python — verificación_setup.py from selenium import webdriver driver = webdriver.Chrome() driver.get("https://www.selenium.dev") print(driver.title) # Imprime el título de la página driver.quit() # Si ves el título en consola, ¡tu setup funciona! python — verificación_setup.py from selenium import webdriver driver = webdriver.Chrome() driver.get("https://www.selenium.dev") print(driver.title) # Imprime el título de la página driver.quit() # Si ves el título en consola, ¡tu setup funciona! python — locators_ejemplos.py from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://ejemplo.com") # Por ID (el más rápido y confiable cuando existe) campo_email = driver.find_element(By.ID, "email") # Por Name campo_pass = driver.find_element(By.NAME, "password") # Por CSS Selector (flexible y legible) boton = driver.find_element(By.CSS_SELECTOR, "button.btn-primary") enlace = driver.find_element(By.CSS_SELECTOR, "a[href='/login']") # Por XPath (el más poderoso, úsalo cuando no hay otra opción) titulo = driver.find_element(By.XPATH, "//h1[@class='title']") texto = driver.find_element(By.XPATH, "//p[contains(text(),'Bienvenido')]") # Por Link Text (para elementos <a>) link = driver.find_element(By.LINK_TEXT, "Iniciar Sesión") driver.quit() python — locators_ejemplos.py from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://ejemplo.com") # Por ID (el más rápido y confiable cuando existe) campo_email = driver.find_element(By.ID, "email") # Por Name campo_pass = driver.find_element(By.NAME, "password") # Por CSS Selector (flexible y legible) boton = driver.find_element(By.CSS_SELECTOR, "button.btn-primary") enlace = driver.find_element(By.CSS_SELECTOR, "a[href='/login']") # Por XPath (el más poderoso, úsalo cuando no hay otra opción) titulo = driver.find_element(By.XPATH, "//h1[@class='title']") texto = driver.find_element(By.XPATH, "//p[contains(text(),'Bienvenido')]") # Por Link Text (para elementos <a>) link = driver.find_element(By.LINK_TEXT, "Iniciar Sesión") driver.quit() python — locators_ejemplos.py from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://ejemplo.com") # Por ID (el más rápido y confiable cuando existe) campo_email = driver.find_element(By.ID, "email") # Por Name campo_pass = driver.find_element(By.NAME, "password") # Por CSS Selector (flexible y legible) boton = driver.find_element(By.CSS_SELECTOR, "button.btn-primary") enlace = driver.find_element(By.CSS_SELECTOR, "a[href='/login']") # Por XPath (el más poderoso, úsalo cuando no hay otra opción) titulo = driver.find_element(By.XPATH, "//h1[@class='title']") texto = driver.find_element(By.XPATH, "//p[contains(text(),'Bienvenido')]") # Por Link Text (para elementos <a>) link = driver.find_element(By.LINK_TEXT, "Iniciar Sesión") driver.quit() python — acciones_basicas.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("https://ejemplo.com") # Click en un botón o enlace driver.find_element(By.ID, "login-btn").click() # Escribir texto en un campo (SendKeys) campo = driver.find_element(By.NAME, "username") campo.clear() # Limpiar primero (buena práctica) campo.send_keys("mi_usuario") # Enviar formulario con Enter campo.send_keys(Keys.RETURN) # Obtener texto de un elemento mensaje = driver.find_element(By.CLASS_NAME, "alert-success") print(mensaje.text) # Obtener valor de un atributo url_imagen = driver.find_element(By.TAG_NAME, "img").get_attribute("src") # Navegar driver.back() driver.forward() driver.refresh() # Maximizar ventana driver.maximize_window() driver.quit() python — acciones_basicas.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("https://ejemplo.com") # Click en un botón o enlace driver.find_element(By.ID, "login-btn").click() # Escribir texto en un campo (SendKeys) campo = driver.find_element(By.NAME, "username") campo.clear() # Limpiar primero (buena práctica) campo.send_keys("mi_usuario") # Enviar formulario con Enter campo.send_keys(Keys.RETURN) # Obtener texto de un elemento mensaje = driver.find_element(By.CLASS_NAME, "alert-success") print(mensaje.text) # Obtener valor de un atributo url_imagen = driver.find_element(By.TAG_NAME, "img").get_attribute("src") # Navegar driver.back() driver.forward() driver.refresh() # Maximizar ventana driver.maximize_window() driver.quit() python — acciones_basicas.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("https://ejemplo.com") # Click en un botón o enlace driver.find_element(By.ID, "login-btn").click() # Escribir texto en un campo (SendKeys) campo = driver.find_element(By.NAME, "username") campo.clear() # Limpiar primero (buena práctica) campo.send_keys("mi_usuario") # Enviar formulario con Enter campo.send_keys(Keys.RETURN) # Obtener texto de un elemento mensaje = driver.find_element(By.CLASS_NAME, "alert-success") print(mensaje.text) # Obtener valor de un atributo url_imagen = driver.find_element(By.TAG_NAME, "img").get_attribute("src") # Navegar driver.back() driver.forward() driver.refresh() # Maximizar ventana driver.maximize_window() driver.quit() python — test_login.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time def test_login_exitoso(): # --- Setup --- driver = webdriver.Chrome() driver.maximize_window() driver.get("https://practicetestautomation.com/practice-test-login/") # --- Acción: ingresar credenciales --- driver.find_element(By.ID, "username").send_keys("student") driver.find_element(By.ID, "password").send_keys("Password123") driver.find_element(By.ID, "submit").click() # --- Espera explícita: aguardar elemento post-login --- wait = WebDriverWait(driver, timeout=10) mensaje = wait.until( EC.visibility_of_element_located((By.CLASS_NAME, "post-title")) ) # --- Validación (Assertion) --- assert "Logged In Successfully" in mensaje.text, \ f"Login falló. Texto encontrado: {mensaje.text}" print("✓ Login exitoso verificado") # --- Teardown --- driver.quit() # Ejecutar el test test_login_exitoso() python — test_login.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time def test_login_exitoso(): # --- Setup --- driver = webdriver.Chrome() driver.maximize_window() driver.get("https://practicetestautomation.com/practice-test-login/") # --- Acción: ingresar credenciales --- driver.find_element(By.ID, "username").send_keys("student") driver.find_element(By.ID, "password").send_keys("Password123") driver.find_element(By.ID, "submit").click() # --- Espera explícita: aguardar elemento post-login --- wait = WebDriverWait(driver, timeout=10) mensaje = wait.until( EC.visibility_of_element_located((By.CLASS_NAME, "post-title")) ) # --- Validación (Assertion) --- assert "Logged In Successfully" in mensaje.text, \ f"Login falló. Texto encontrado: {mensaje.text}" print("✓ Login exitoso verificado") # --- Teardown --- driver.quit() # Ejecutar el test test_login_exitoso() python — test_login.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time def test_login_exitoso(): # --- Setup --- driver = webdriver.Chrome() driver.maximize_window() driver.get("https://practicetestautomation.com/practice-test-login/") # --- Acción: ingresar credenciales --- driver.find_element(By.ID, "username").send_keys("student") driver.find_element(By.ID, "password").send_keys("Password123") driver.find_element(By.ID, "submit").click() # --- Espera explícita: aguardar elemento post-login --- wait = WebDriverWait(driver, timeout=10) mensaje = wait.until( EC.visibility_of_element_located((By.CLASS_NAME, "post-title")) ) # --- Validación (Assertion) --- assert "Logged In Successfully" in mensaje.text, \ f"Login falló. Texto encontrado: {mensaje.text}" print("✓ Login exitoso verificado") # --- Teardown --- driver.quit() # Ejecutar el test test_login_exitoso() python — waits_ejemplo.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.support.ui import FluentWait from datetime import timedelta # IMPLICIT WAIT (evitar mezclarlo con Explicit Waits) driver.implicitly_wait(5) # espera hasta 5 seg al buscar elementos # EXPLICIT WAIT (recomendado) wait = WebDriverWait(driver, timeout=10) # Esperar a que el botón sea clickeable boton = wait.until(EC.element_to_be_clickable((By.ID, "submit"))) boton.click() # Esperar texto específico en un elemento wait.until(EC.text_to_be_present_in_element( (By.ID, "-weight: 500;">status"), "Completado" )) # FLUENT WAIT (polling cada 2 seg, ignora NoSuchElementException) fluent = FluentWait(driver) \ .with_timeout(timedelta(seconds=30)) \ .polling_every(timedelta(seconds=2)) \ .ignoring(NoSuchElementException) elemento = fluent.until(lambda d: d.find_element(By.ID, "carga-lenta")) python — waits_ejemplo.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.support.ui import FluentWait from datetime import timedelta # IMPLICIT WAIT (evitar mezclarlo con Explicit Waits) driver.implicitly_wait(5) # espera hasta 5 seg al buscar elementos # EXPLICIT WAIT (recomendado) wait = WebDriverWait(driver, timeout=10) # Esperar a que el botón sea clickeable boton = wait.until(EC.element_to_be_clickable((By.ID, "submit"))) boton.click() # Esperar texto específico en un elemento wait.until(EC.text_to_be_present_in_element( (By.ID, "-weight: 500;">status"), "Completado" )) # FLUENT WAIT (polling cada 2 seg, ignora NoSuchElementException) fluent = FluentWait(driver) \ .with_timeout(timedelta(seconds=30)) \ .polling_every(timedelta(seconds=2)) \ .ignoring(NoSuchElementException) elemento = fluent.until(lambda d: d.find_element(By.ID, "carga-lenta")) python — waits_ejemplo.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.support.ui import FluentWait from datetime import timedelta # IMPLICIT WAIT (evitar mezclarlo con Explicit Waits) driver.implicitly_wait(5) # espera hasta 5 seg al buscar elementos # EXPLICIT WAIT (recomendado) wait = WebDriverWait(driver, timeout=10) # Esperar a que el botón sea clickeable boton = wait.until(EC.element_to_be_clickable((By.ID, "submit"))) boton.click() # Esperar texto específico en un elemento wait.until(EC.text_to_be_present_in_element( (By.ID, "-weight: 500;">status"), "Completado" )) # FLUENT WAIT (polling cada 2 seg, ignora NoSuchElementException) fluent = FluentWait(driver) \ .with_timeout(timedelta(seconds=30)) \ .polling_every(timedelta(seconds=2)) \ .ignoring(NoSuchElementException) elemento = fluent.until(lambda d: d.find_element(By.ID, "carga-lenta")) python — pages/login_page.py from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: # Locators centralizados: si la UI cambia, solo editas aquí CAMPO_USUARIO = (By.ID, "username") CAMPO_PASSWORD = (By.ID, "password") BOTON_LOGIN = (By.ID, "submit") MENSAJE_ERROR = (By.ID, "error") def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) def ingresar_usuario(self, usuario): campo = self.wait.until(EC.visibility_of_element_located(self.CAMPO_USUARIO)) campo.clear() campo.send_keys(usuario) def ingresar_password(self, password): self.driver.find_element(*self.CAMPO_PASSWORD).send_keys(password) def hacer_click_login(self): self.driver.find_element(*self.BOTON_LOGIN).click() def login(self, usuario, password): # Método de alto nivel: la acción completa de login self.ingresar_usuario(usuario) self.ingresar_password(password) self.hacer_click_login() def obtener_mensaje_error(self): return self.driver.find_element(*self.MENSAJE_ERROR).text python — pages/login_page.py from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: # Locators centralizados: si la UI cambia, solo editas aquí CAMPO_USUARIO = (By.ID, "username") CAMPO_PASSWORD = (By.ID, "password") BOTON_LOGIN = (By.ID, "submit") MENSAJE_ERROR = (By.ID, "error") def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) def ingresar_usuario(self, usuario): campo = self.wait.until(EC.visibility_of_element_located(self.CAMPO_USUARIO)) campo.clear() campo.send_keys(usuario) def ingresar_password(self, password): self.driver.find_element(*self.CAMPO_PASSWORD).send_keys(password) def hacer_click_login(self): self.driver.find_element(*self.BOTON_LOGIN).click() def login(self, usuario, password): # Método de alto nivel: la acción completa de login self.ingresar_usuario(usuario) self.ingresar_password(password) self.hacer_click_login() def obtener_mensaje_error(self): return self.driver.find_element(*self.MENSAJE_ERROR).text python — pages/login_page.py from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: # Locators centralizados: si la UI cambia, solo editas aquí CAMPO_USUARIO = (By.ID, "username") CAMPO_PASSWORD = (By.ID, "password") BOTON_LOGIN = (By.ID, "submit") MENSAJE_ERROR = (By.ID, "error") def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) def ingresar_usuario(self, usuario): campo = self.wait.until(EC.visibility_of_element_located(self.CAMPO_USUARIO)) campo.clear() campo.send_keys(usuario) def ingresar_password(self, password): self.driver.find_element(*self.CAMPO_PASSWORD).send_keys(password) def hacer_click_login(self): self.driver.find_element(*self.BOTON_LOGIN).click() def login(self, usuario, password): # Método de alto nivel: la acción completa de login self.ingresar_usuario(usuario) self.ingresar_password(password) self.hacer_click_login() def obtener_mensaje_error(self): return self.driver.find_element(*self.MENSAJE_ERROR).text python — tests/test_login.py (usando POM) from selenium import webdriver from pages.login_page import LoginPage def test_login_credenciales_validas(): driver = webdriver.Chrome() driver.get("https://practicetestautomation.com/practice-test-login/") # El test es limpio y legible: sin un solo locator login = LoginPage(driver) login.login("student", "Password123") assert "Logged In Successfully" in driver.title or \ driver.current_url != "https://practicetestautomation.com/practice-test-login/" driver.quit() def test_login_credenciales_invalidas(): driver = webdriver.Chrome() driver.get("https://practicetestautomation.com/practice-test-login/") login = LoginPage(driver) login.login("usuario_falso", "clave_incorrecta") error = login.obtener_mensaje_error() assert "Your username is invalid!" in error driver.quit() python — tests/test_login.py (usando POM) from selenium import webdriver from pages.login_page import LoginPage def test_login_credenciales_validas(): driver = webdriver.Chrome() driver.get("https://practicetestautomation.com/practice-test-login/") # El test es limpio y legible: sin un solo locator login = LoginPage(driver) login.login("student", "Password123") assert "Logged In Successfully" in driver.title or \ driver.current_url != "https://practicetestautomation.com/practice-test-login/" driver.quit() def test_login_credenciales_invalidas(): driver = webdriver.Chrome() driver.get("https://practicetestautomation.com/practice-test-login/") login = LoginPage(driver) login.login("usuario_falso", "clave_incorrecta") error = login.obtener_mensaje_error() assert "Your username is invalid!" in error driver.quit() python — tests/test_login.py (usando POM) from selenium import webdriver from pages.login_page import LoginPage def test_login_credenciales_validas(): driver = webdriver.Chrome() driver.get("https://practicetestautomation.com/practice-test-login/") # El test es limpio y legible: sin un solo locator login = LoginPage(driver) login.login("student", "Password123") assert "Logged In Successfully" in driver.title or \ driver.current_url != "https://practicetestautomation.com/practice-test-login/" driver.quit() def test_login_credenciales_invalidas(): driver = webdriver.Chrome() driver.get("https://practicetestautomation.com/practice-test-login/") login = LoginPage(driver) login.login("usuario_falso", "clave_incorrecta") error = login.obtener_mensaje_error() assert "Your username is invalid!" in error driver.quit() - ¿Por qué escribo sobre Selenium? De la frustración a la automatización - Introducción e Historia - Características Principales - Componentes del Ecosistema - Drivers y Soporte - Lenguajes Soportados - Instalación y Configuración - Beneficios de Automatizar - Conceptos Clave y Código - Puntos Críticos de Aprendizaje - Documentación y Comunidad - 2004: Nacimiento de Selenium Core. Jason Huggins, ingeniero de ThoughtWorks, crea una herramienta interna para automatizar pruebas de la aplicación de gestión de tiempo de su empresa. La llamó "JavaScript Test Runner" y luego la renombró Selenium. - 2006: Selenium IDE y Selenium RC. Paul Hammant desarrolla Selenium Remote Control (RC), permitiendo ejecutar pruebas en múltiples lenguajes. Simon Stewart comienza a trabajar en WebDriver como proyecto en Google. - 2008: Unificación histórica. Los equipos de Selenium RC y WebDriver se fusionan. Nace Selenium 2 con WebDriver como componente central. Este fue un punto de inflexión definitivo para la herramienta. - 2016: Selenium 3. Se lanza como una gran actualización que elimina el antiguo Selenium RC y consolida WebDriver como el núcleo, adoptando además el protocolo W3C WebDriver. - 2021 - hoy: Selenium 4. La versión actual trae soporte nativo al protocolo W3C, mejor integración con Chrome DevTools Protocol (CDP), soporte para ventanas relativas, y una API más limpia e intuitiva. Esta es la versión que aprenderás en esta guía. - Open Source y Gratuito Sin costos de licencia. La comunidad global lo mantiene activamente bajo licencia Apache 2.0. - Multi-navegador Compatible con Chrome, Firefox, Safari, Edge y Opera. Prueba en todos los entornos de tus usuarios. - Multi-lenguaje Escribe tus pruebas en Java, Python, C#, JavaScript, Ruby o Kotlin - Integración con CI/CD Se integra con Jenkins, GitHub Actions, GitLab CI, Docker y frameworks como TestNG o JUnit. - Ejecución en Grid Distribuye pruebas en múltiples máquinas simultáneamente para reducir tiempo de ejecución. - Protocolo W3C Selenium 4 es 100% compatible con el estándar W3C WebDriver, garantizando estabilidad a largo plazo. - Prototipado rápido de pruebas - Generar código base que luego puedes refinar en WebDriver - Testers no técnicos que quieren automatizar tareas sencillas - ChromeDriver Para Google Chrome. Mantenido por el equipo de Chromium. - GeckoDriver Para Mozilla Firefox. Mantenido por Mozilla. - EdgeDriver Para Microsoft Edge (Chromium). Mantenido por Microsoft. - SafariDriver Para Safari. Integrado en macOS, sin descarga adicional. - Linux (Ubuntu, Debian, RHEL) - Docker Containers - Java El más popular en empresas. Amplio ecosistema con TestNG y JUnit. - Python Sintaxis simple, ideal para principiantes. Muy usado en IA/ML teams. - C# Preferido en equipos .NET y Microsoft. Integra con NUnit/MSTest. - JavaScript Perfecto para equipos frontend. Funciona con Mocha, Jest, WebdriverIO. - Ruby Popular en el ecosistema Rails. Elegante y expresivo. - Ahorro de tiempo masivo: Una suite de regresión que toma 8 horas de forma manual puede ejecutarse en 30 minutos de forma automatizada, liberando tiempo para pruebas exploratorias de mayor valor. - Precisión y consistencia: Un script automatizado ejecuta exactamente los mismos pasos cada vez, sin el cansancio o descuidos humanos que aparecen en la prueba número 50 del día. - Reusabilidad del código: Un test escrito una vez puede ejecutarse miles de veces, en múltiples entornos, configuraciones y datos de prueba diferentes. - Retroalimentación temprana: Integrado en CI/CD, Selenium puede detectar regresiones en minutos después de cada commit, no días después del deployment. - Cobertura multi-entorno: Con Selenium Grid puedes ejecutar la misma prueba en Chrome, Firefox y Edge simultáneamente, garantizando compatibilidad cross-browser. - Documentación viva: Los scripts de Selenium, bien escritos, documentan el comportamiento esperado del sistema de forma ejecutable. - selenium.dev/documentation Documentación oficial. La fuente de verdad para APIs, guías y cambios por versión. - The Internet (Heroku) the-internet.herokuapp.com — colección de escenarios de UI complejos para practicar: dropdowns, iframes, alerts, auth. - r/QualityAssurance Comunidad activa en Reddit con discusiones sobre herramientas, carrera y mejores prácticas de QA Automation. - Practice Test Automation practicetestautomation.com — sitios de práctica diseñados específicamente para aprender Selenium. - Stack Overflow — selenium +100,000 preguntas etiquetadas con [selenium]. Si tienes un error, probablemente ya fue resuelto aquí. - Ministry of Testing ministryoftesting.com — comunidad global de testers con artículos, cursos y una comunidad muy activa. - No memorices, practica. Selenium se aprende escribiendo código, no leyendo. Después de cada sección, abre tu IDE y escribe los ejemplos desde cero. - Aprende a usar las DevTools del navegador. F12 es tu mejor aliado. Inspeccionar el HTML, copiar XPaths y depurar selectores CSS es una habilidad diaria en el trabajo de un Automation Tester. - Nunca uses time.sleep(). Esta línea es la señal de alerta en cualquier code review. Siempre usa WebDriverWait con condiciones explícitas. Tus pruebas serán más rápidas y confiables. - Siempre llama driver.quit() al final. Diferente a driver.close(), quit() cierra el driver y libera todos los recursos. Usa fixtures de pytest o bloques try/finally para garantizarlo. - Empieza con un sitio de práctica, no con tu aplicación de trabajo. Practica en sitios como the-internet.herokuapp.com o practicetestautomation.com antes de automatizar en producción. - Aprende pytest desde el principio. No escribas funciones sueltas. pytest es el framework de testing estándar en Python y te dará estructura, reportes y fixtures desde el día uno. - Un test debe verificar una sola cosa. Evita los tests "god test" que verifican 15 cosas a la vez. Tests pequeños, enfocados y con nombres descriptivos son más fáciles de depurar cuando fallan. - Implementa POM desde tu primer proyecto real. Puede parecer overhead al inicio, pero te salvará de semanas de refactoring cuando el equipo de desarrollo cambie la UI. Hazlo hábito desde hoy. - Usa control de versiones desde el día uno. Tus scripts de automatización son código de producción. Commit frecuente en Git, ramas para nuevas features, pull requests para revisión. - Lee los errores completos. Un NoSuchElementException, StaleElementReferenceException o TimeoutException tiene una causa específica. Aprende qué significa cada uno; son tus mejores maestros.