<Hola>, en el post anterior vimos cómo realizar una búsqueda de los selectores ID y CLASS, ahora vamos a visitar 2 páginas web más del proyecto y a controlar los errores que nos marca, además tendremos la opción de guardar algunos logs.
Lo que buscamos es tener un mensaje mas certero al tener un error, en la siguiente imagen vemos los mensajes sin control de errores

Aquí con control de errores

Modificamos un poco el inicio del proyecto
from selenium import webdriver
from process.frontend.home import ProcessHomeFront
from process.frontend.contact import ProcessContactFront
from process.frontend.blog import ProcessBlogFront
#open browser
driver = webdriver.Chrome()
driver.get("http://localhost/")
process_home_front = ProcessHomeFront( driver )
process_home_front.start_process()
process_contact_front = ProcessContactFront( driver )
process_contact_front.start_process()
process_blog_front = ProcessBlogFront( driver )
process_blog_front.start_process()
driver.quit()
Veremos unas modificaciones, se agregan por ejemplo 3 clases nuevas, cada una con su segmento de código con el fin de asignar a cada una sus propias pruebas, nos vamos con la clase “ProcessHomeFront”, vemos el código a continuación
from own_class.errorselenium import ErrorSelenium
class ProcessHomeFront:
def __init__(self, webdriver):
self.webdriver = webdriver
def start_process(self):
detect_error = ErrorSelenium( self.webdriver )
detect_error.exist_element_by_class("copyright_left")
Vamos a desglosar el código, al inicio importamos una pequeña librería que adaptamos para el manejo de errores
from own_class.errorselenium import ErrorSelenium
Declaramos la clase
class ProcessHomeFront:
y también declaramos el constructor donde esperamos el parámetro del “webdriver” de selenium
def __init__(self, webdriver):
self.webdriver = webdrive
Para terminar con la declaración de una función
def start_process(self):
detect_error = ErrorSelenium( self.webdriver )
detect_error.exist_element_by_class("copyright_left")
Lo que hace esta función es verificar si existe la clase “copyright_left” en el contenido html, el siguiente fragmento es donde válida esto, más tarde veremos el código completo de la clase “ErrorSelenium”, por el momento dejo un fragmento del código
def exist_element_by_class(self, arg):
try:
self.webdriver.find_element(By.CLASS_NAME, arg)
except NoSuchElementException:
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
get_url = self.webdriver.current_url
print("The class do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )
self.webdriver.quit()
quit()
Lo que he visto en varios tutoriales es que colocan el siguiente código
self.webdriver.find_element(By.CLASS_NAME, arg)
sin control de excepciones, intente hacer un manejador de errores con las sentencias “try” y “except”, espero que nos sirva para este tutorial. Como podemos observar la primera línea de este fragmento de código es para declarar la función.
def exist_element_by_class(self, arg):
Esta función recibe 2 parámetros uno propio de python y el otro parámetro es el selector clase que nosotros queremos que busque. En el siguiente bloque de código utilizaremos la sentencia “try”
try:
self.webdriver.find_element(By.CLASS_NAME, arg)
esta función se activa si dentro de la ejecución aparece un error, en caso de que exista el error se ejecuta el siguiente bloque
except NoSuchElementException:
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
get_url = self.webdriver.current_url
print("The class do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )
self.webdriver.quit()
quit()
La palabra o sentencia “except” es una palabra predefinida del lenguaje Python, la cual tiene un parámetro de error “NoSuchElementException”, que nos ayudará a detectar el error de cuando no existe la “clase” o “id”, el proyecto que estoy haciendo pruebas esta hecho en Laravel por eso el motivo de la siguiente línea de código
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
en Laravel cuando encuentra un error se despliega una vista con el detalle del error, lo que hacemos aquí es buscar el mensaje principal del error, con la siguiente línea de código obtenemos la Url
get_url = self.webdriver.current_url
Ahora imprimimos los mensajes, el primer mensaje nos notifica que no existe la clase y luego de esto se imprime en colores rojo el mensaje de error de Laravel y la página donde está sucediendo.
print("The class do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
Para tener un registro de lo que está sucediendo, se activó la librería Log, el cual nos llevará un historial de los errores de la aplicación
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )

Por último las siguiente dos líneas de código nos ayudará a cerrar el proceso del “webdriver” y del proceso principal.
self.webdriver.quit()
quit()
Las otras dos clases son iguales a ProcessHomeFront, este archivo es ProcessContactFront.py, el código es
from own_class.errorselenium import ErrorSelenium
class ProcessContactFront:
def __init__(self, webdriver):
self.webdriver = webdriver
def start_process(self):
self.webdriver.get('http://localhost/contact')
detect_error = ErrorSelenium( self.webdriver )
detect_error.exist_element_by_class("copyright_left")
Y por último la clase ProcessBlogFront
from own_class.errorselenium import ErrorSelenium
class ProcessBlogFront:
def __init__(self, webdriver):
self.webdriver = webdriver
def start_process(self):
self.webdriver.get('http://localhost/blog')
detect_error = ErrorSelenium( self.webdriver )
detect_error.exist_element_by_class("copyright_left")
Las líneas de código son prácticamente igual, solo cambia que se agrega la línea de código “self.webdriver.get”, que nos permite redirigir el navegador hacia esa página, en este segmento nos vamos a enfocar en la clase que importamos al inicio, “ErrorSelenium”, aquí está el código
import logging
import datetime
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from .bcolors import bcolors
class ErrorSelenium:
def __init__(self, webdriver):
self.webdriver = webdriver
x = datetime.datetime.now()
logging.basicConfig(filename='my-project/tests/Selenium/myapp.log', level=logging.INFO)
logging.info(f"Started {x}")
def exist_element_by_class(self, arg):
try:
self.webdriver.find_element(By.CLASS_NAME, arg)
except NoSuchElementException:
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
get_url = self.webdriver.current_url
print("The class do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )
self.webdriver.quit()
quit()
def exist_element_by_id(self, arg):
try:
self.webdriver.find_element(By.ID, arg)
except NoSuchElementException:
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
get_url = self.webdriver.current_url
print("The id do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )
self.webdriver.quit()
quit()
Vamos a desglosar un poco el código, en las dos primeras líneas de código podemos observar que se importa las librerías, una para guardar un registro de las actividades y la otra librería para utilizar fechas
import logging
import datetime
También importamos librerías dedicadas a Selenium,
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
Por último de las importaciones agregamos una pequeña clase que nos servirá para ver los mensajes de la terminal en colores.
from .bcolors import bcolors
En el siguiente código, vemos al constructor
def __init__(self, webdriver):
self.webdriver = webdriver
x = datetime.datetime.now()
logging.basicConfig(filename='my-project/tests/Selenium/myapp.log', level=logging.INFO)
logging.info(f"Started {x}")
El constructor necesita el “webdriver” como parámetro para realizar las comprobaciones, también podemos observar el uso de un log que nos permite saber en qué fecha fue ejecutado. A continuación veremos la primera función que nos servirá para buscar clases en el contenido HTML
def exist_element_by_class(self, arg):
try:
self.webdriver.find_element(By.CLASS_NAME, arg)
except NoSuchElementException:
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
get_url = self.webdriver.current_url
print("The class do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )
self.webdriver.quit()
quit()
Esta función espera un argumento que es el nombre de la clase, si no colocamos el “try” la función “find_element” nos devuelve un error muy detallada que por el momento no deseamos, en caso de encontrar ese error buscamos la clase “line-clamp-2” que nos proporciona laravel cuando un error pasa, este mensaje será incluido en los logs y será mostrado en la ejecución del código.
Seguimos con la función “exist_element_by_id”
def exist_element_by_id(self, arg):
try:
self.webdriver.find_element(By.ID, arg)
except NoSuchElementException:
error = self.webdriver.find_element(By.CLASS_NAME, "line-clamp-2").text
get_url = self.webdriver.current_url
print("The id do not exist")
print(f"{bcolors.FAIL} MSG: {error} | PAGE: {str(get_url)} {bcolors.ENDC}")
logging.warning( f"MSG: {error} | PAGE: {str(get_url)}" )
self.webdriver.quit()
quit()
Es prácticamente igual que la función “exist_element_by_class”, en caso de no encontrar el “id” que se pasa a través del argumento, este busca la clase “line-clamp-2” de laravel para mostrar el mensaje de error.
Me faltaba incluir la clase que maneja los colores en el texto de la terminal.
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
Para ejecutar las pruebas solo ejecutamos el siguiente comando
python .\{ruta}\start.py

Con esto concluimos este pequeño tutorial, que nos permite saber cómo visitar 1 o más páginas dentro de la prueba, manejar errores cuando no se encuentran los selectores “class” e “id”, también agregamos el registro de las actividades que realiza el código.
</Saludos>