Blog
El proyecto final para este curso, es un ejemplo de la vida real de un E2E test, osea un test de Punto a Punto (End to End) de comienzo a final. Espero les guste, recibí este mismo proyecto no hace mucho así que realmente es un proyecto que pueden darle en algún momento de su vida diaria.
Objetivo del Test
Poder simular la llegada de un usuario que entra al sitio web, busca un producto, procede a añadirlo al carrito de compras, y finalizar la compra, llenando el formulario hasta el momento que pide sus datos de su tarjeta de crédito.
Historia del Usuario
A menudo cuando se realizan este tipo de proyectos, se nos da una lista de steps (pasos) para poder entender que es lo que nos pide el jefe qué hagamos, y lo que desea obtener, esto es importante pues necesitamos seguir estos pasos, ya que nos dará una idea de lo que espera el usuario que realice el sistema.
Como visitante quiero:
- Buscar un producto desde una caja de búsqueda
- Obtener resultados que contengan mi búsqueda
- Que al dar click en una de las búsquedas me lleve a la página de detalle del producto
- Que al añadir al carrito pueda comprobar que el mismo producto que añadí es el que tengo en mi carrito de compras con su mismo precio
- Poder pagar mi producto y entrar como invitado sin tener que crearme una cuenta
- Llenar los datos necesarios
- Darme diferentes métodos de pago.
Ahora bueno necesitamos trasladar estas historias de usuario del lenguaje natural a un lenguaje sin ambigüedades para poder programarlo, a lo que se llama Crear Escenario del Test en términos técnicos de automatización.
Test Scenario
- Entrar al sitio www.gearbest.com
- Comprobar que el titulo contenga Gearbest
- Buscar por producto llamado: xiaomi mi a2 lite
- Clickear el primer resultado (Guardar el SKU y el Precio)
- Guardar el Product code o Código de producto
- Guardar el precio
- Click en Buy Now
- Click en ‘Continue as Guest”
- Llenar el formulario
- Verificar que el precio y el código del producto sea el mismo
- Click en complete
Como se puede leer, estos pasos son más precisos, y fuera de muchas ambigüedades que teníamos con el lenguaje natural. Tenemos lo necesario para empezar a nuestro proyecto E2E de automatización con Selenium en Python.
Empezando a automatizar el proyecto
Importando librerias
from selenium import webdriver from selenium.webdriver.common.keys import Keys import time
Importamos las librerías necesarias, selenium, y en este caso time para los wait. Lo más común del mundo.
Paso 0
driver = webdriver.Chrome() driver.implicitly_wait(25)
Inicializamos el webdriver, en este caso estaremos usando Google Chrome en su última versión. La segunda línea está configurando el tiempo de espera máximo al buscar un elemento, bastante útil para sitios web que cargan los recursos a demanda, o demoran bastante. Se recomienda no abusar del mismo.
Paso 1 – Entrar al sitio www.gearbest.com
driver.get("http://www.gearbest.com")
Nos dirigimos a nuestro sitio web, en este caso la tienda Gearbest. Una vez termine de cargar, procederá al siguiente paso.
Paso 2 – Comprobar que el titulo contenga Gearbest
assert "Gearbest" in driver.title
Se nos pide que comprobemos que el título del sitio contenga la palabra Gearbest.
Paso 3 – Buscar por producto llamado: Xiaomi Redmi 6A 4G
searchedWord = driver.find_element_by_id("js-iptKeyword") searchedWord.clear() searchedWord.send_keys("Xiaomi Redmi 6A 4G ") searchedWord.send_keys(Keys.RETURN)
Aprovechamos que la caja de texto hace uso de los id, como saben cuándo se trata de obtener la ubicación de un elemento la prioridad es siempre el id de tenerlo. La siguiente línea borra el contenido de la caja en caso de tener algo escrito por defecto. Procedemos a enviar las teclas de nuestra búsqueda en este caso “Xiaomi Redmi 6A 4G”, y mandar el Enter para empezar a buscar.
Paso 4 – Clickear el primer resultado
product_element = driver.find_element_by_xpath('(//a[contains(.,"Xiaomi Redmi 6A 4G")])[1]') product_element.click()
Una vez tengamos la lista de resultados, procedemos a clickear el primer resultado. Para ello haremos una consulta un poco compleja.
(//a[contains(.,"Xiaomi Redmi 6A 4G")])[1]
¿por qué los paréntesis? porque la consulta: //a[contains(.,”Xiaomi Redmi 6A 4G” devuelve todos los resultados, si la lista tuviera 20 resultados por página obtendría 20 coincidencias con mi búsqueda. Por lo que si encerramos en un paréntesis, podemos hacer uso de los corchetes para referirnos, como si de un array se tratare, la posición que necesitamos de todas las coincidencias, en nuestro caso sería 1, ya que este arreglo empieza con 1 y no 0. Procedemos a darle click a ese resultado.
Paso 4.1 – Guardar el código del producto
product_sku_element = driver.find_element_by_xpath('//a[@class="goodsIntro_btnFav js-btnGoodsCollect js-trackBtnGoodsCollect"]') product_sku = product_sku_element.get_attribute("data-sku")
Necesitamos guardar el código de producto ¿porque? porque necesitamos luego comparar luego en el carrito de compras, si es el mismo producto único que el que añadimos. Este tipo de comprobaciones son de lo más normal y necesarios.
product_sku_element tendría este html como resultado:
<a href="javascript:;" class="goodsIntro_btnFav js-btnGoodsCollect js-trackBtnGoodsCollect" data-sku="274825301" data-warehouse="1527929"> <span class="goodsIntro_favIcon"> <i class="sp-collect"></i> </span> Add to Favorites <b class="goodsIntro_favCount">(<span class="js-favCount">999+</span>)</b> </a>
Pero solo nos interesa el valor del data-sku, por lo que usaremos el .get_attribute(“data-sku”) dentro del elemento y así lo que guardaremos al final será 274825301, el sku del producto.
Paso 4.2 Guardar el precio del producto
product_price_element = driver.find_element_by_xpath('//span[@class="goodsIntro_price js-currency js-panelIntroPrice"]') product_price = product_price_element.get_attribute("data-currency")
Se hace el mismo procedimiento, en este caso necesitamos el precio, que se encuentra en otra variable.
product_price_element tiene el siguiente html:
<span class="goodsIntro_price js-currency js-panelIntroPrice" data-currency="119.04" data-wrap="0" data-round="2">$119.04</span>
Como imaginarás, el atributo data-currency es el que contiene el precio.
Por lo que usaremos el ya conocido get_attribute(“data_currency”), y bingo obtenemos 119.04 mismo que almacenaremos en la variable product_price
Paso 5 – Click en Buy Now
buy_now_button = driver.find_element_by_xpath('(//a[@class="btn big uibtn-buynow js-btnGoodsBuyNow js-trackBtnBuyNow "])[1]') buy_now_button.click()
Procedemos a hallar el xpath del botón “Buy Now”, en este caso al no tener un id, vamos por su class, pero se usan las mismas clases en 2 lugares diferentes, no queda de otra que volver a usar el método anterior, para solo seleccionar la primera coincidencia.
Paso 6 – Click en ‘Continue as Guest’
continue_as_guest = driver.find_element_by_xpath('//a[@class="btn visitorBtn"]') continue_as_guest.click()
No hay mucho que explicar, un sencillo selector por xpath, y darle click al mismo.
Paso 7 – Llenar todo el formulario
driver.find_element_by_name("firstName").send_keys("Izzy") driver.find_element_by_name("lastName").send_keys("Stark") driver.find_element_by_name("email").send_keys("Izzy@correo.com") driver.find_element_by_name("postalCode").send_keys("3131") driver.find_element_by_name("addressLine1").send_keys("Avenida 3 pasos al frente #333") driver.find_element_by_xpath('(//p[@class="address_dropdownTitle"])[2]').click() driver.find_element_by_xpath("//li[contains(., 'Santa Cruz')]").click() driver.find_element_by_name("cityName").send_keys("Santa Cruz") driver.find_element_by_class_name("address_phoneInt").send_keys("77026747") driver.find_element_by_xpath('//*[@class="address_btn btn middle strong"]').click()
Ya vamos casi terminando. En este caso viene la parte más morosa, y es para llenar el formulario para el envió. El cual es bastante fácil, ya que el formulario tiene el atributo name en todos sus campos, y solo sería cuestión de enviar las palabras a esos campos.
El único caso que no hemos visto es el seleccionar de los dropdown, en este caso, el sitio tiene una implementación personalizada de un dropdown, por lo que les explicare cual ha sido mi estrategia para seleccionar de un dropdown custom, las cuales están en estas líneas de código:
driver.find_element_by_xpath('(//p[@class="address_dropdownTitle"])[2]').click() driver.find_element_by_xpath("//li[contains(., 'Santa Cruz')]").click()
La primera línea, vemos que su html que obtiene es:
<p class="address_dropdownTitle"> <span>Please Select</span> <i class="icon-arrow-down1"></i> </p>
Lo cual no se parece nada al tipico dropdown de un html que es:
<select> <option value="volvo">Volvo</option> <option value="saab">Saab</option> <option value="mercedes">Mercedes</option> <option value="audi">Audi</option> </select>
Por lo que en estos casos tendremos que “arreglárnosla” de otra manera.
Por lo que primero A) haremos un click sobre el <p class=address_dropdownTitle”> que simula ser un dropdown, y ahora que esta visible B) podremos dar click sobre cualquiera de sus elementos, para ello tenemos que buscar el path de los ítems de ese dropdown ya que en este caso están fuera del contenedor.
<ul class="address_selectList siteScroll"> <li class="address_selectItem">El Beni</li> <li class="address_selectItem">Cochabamba</li> <li class="address_selectItem">Chuquisaca</li> <li class="address_selectItem">La Paz</li> <li class="address_selectItem">Pando</li> <li class="address_selectItem">Oruro</li> <li class="address_selectItem">Potosi</li> <li class="address_selectItem">Santa Cruz</li> <li class="address_selectItem">Tarija</li> </ul>
Entonces procedo a seleccionar el que contiene “Santa Cruz”. Eso esta en la segunda línea de código de más arriba.
¿Qué hubiera pasado si directamente hubiera dado click al elemento “Santa Cruz?, adivinaste, hubiera obtenido un error de Selenium diciendo que no puede darle click a un elemento que no esta visible.
Paso 8 – Verificar que el código del producto y el precio sea el mismo.
product_price_in_script = '//script[contains(@src, "{}")]'.format(product_price) text = driver.find_element_by_xpath(product_price_in_script).get_attribute("src") assert product_price in text assert product_sku in driver.page_source
Bueno ya vamos terminando, en este caso, nos faltaría obtener el precio del producto y el código del producto dentro del carrito de compras. Por lo que usaremos un método un poco más rebuscado, ya que el único lugar es el código fuente para obtenerlo.
Las últimas dos líneas, son los assert, que nos aseguran que se cumpla la condición de que el precio del producto que habíamos mencionado antes, esté dentro de la página del carrito de compras, de encontrarse pasa la verificación de esa línea a la verificación del código del producto. De no hallarse el mismo producto y el mismo precio (una estafa, o un error del sistema), no pasará a las siguientes líneas.
Paso 9 – Click en “Complete”
driver.find_element_by_xpath('//*[@class="ckOl_totalBtn btn middle strong"]').click()
El último paso es super fácil, es nada más que terminar el proceso de compras. Inmediatamente la siguiente pantalla nos pedirá nuestros datos de nuestra tarjeta.
Y eso sería todo el proyecto, aquí abajo tienes el código completo para correrlo en tu máquina.
from selenium import webdriver from selenium.webdriver.common.keys import Keys import time driver = webdriver.Chrome() # 1. Entrar al sitio www.gearbest.com driver.get("http://www.gearbest.com") driver.implicitly_wait(25) # 2. Comprobar que el titulo contenga Gearbest assert "Gearbest" in driver.title # 3. Buscar por producto llamado: Xiaomi Redmi 6A 4G searchedWord = driver.find_element_by_id("js-iptKeyword") searchedWord.clear() searchedWord.send_keys("Xiaomi Redmi 6A 4G ") searchedWord.send_keys(Keys.RETURN) # 4. Clickear el primer resultado (Guardar el SKU y el Precio) product_element = driver.find_element_by_xpath('(//a[contains(.,"Xiaomi Redmi 6A 4G")])[1]') product_name = product_element.text #product_code_element = driver.find_element_by_xpath('(//a[contains(.,"Xiaomi A2")])[1]/ancestor::li[@data-id]') #product_code = product_code_element.get_attribute("data-id") product_element.click() # 4.1 Guardar el Product code o Código de producto product_sku_element = driver.find_element_by_xpath('//a[@class="goodsIntro_btnFav js-btnGoodsCollect js-trackBtnGoodsCollect"]') product_sku = product_sku_element.get_attribute("data-sku") print(product_sku) # 4.2 Guardar el precio product_price_element = driver.find_element_by_xpath('//span[@class="goodsIntro_price js-currency js-panelIntroPrice"]') product_price = product_price_element.get_attribute("data-currency") print(product_price) # 5. Click en Buy Now buy_now_button = driver.find_element_by_xpath('(//a[@class="btn big uibtn-buynow js-btnGoodsBuyNow js-trackBtnBuyNow "])[1]') buy_now_button.click() # 6. Click en 'Continue as Guest" continue_as_guest = driver.find_element_by_xpath('//a[@class="btn visitorBtn"]') continue_as_guest.click() # 7. Llenar el formulario driver.find_element_by_name("firstName").send_keys("Isaac") driver.find_element_by_name("lastName").send_keys("Zarzuri") driver.find_element_by_name("email").send_keys("Izzy@correo.com") time.sleep(10) driver.find_element_by_name("postalCode").send_keys("3131") driver.find_element_by_name("addressLine1").send_keys("Avenida 3 pasos al frente #333") driver.find_element_by_xpath('(//p[@class="address_dropdownTitle"])[2]').click() driver.find_element_by_xpath("//li[contains(., 'Santa Cruz')]").click() #driver.find_element_by_name("province").send_keys("Santa Cruz") driver.find_element_by_name("cityName").send_keys("Santa Cruz") driver.find_element_by_class_name("address_phoneInt").send_keys("77026747") driver.find_element_by_xpath('//*[@class="address_btn btn middle strong"]').click() 8. Verificar que el precio y el código del producto sea el mismo time.sleep(5) product_price_in_script = '//script[contains(@src, "{}")]'.format(product_price) print(product_price_in_script) text = driver.find_element_by_xpath(product_price_in_script).get_attribute("src") print(text) assert product_price in text assert product_sku in driver.page_source # 9. Click en complete driver.find_element_by_xpath('//*[@class="ckOl_totalBtn btn middle strong"]').click() # Finished test :) #assert "No results found." not in driver.page_source
Reto
Como reto tienes usar cualquier otra tienda online, buscar 3 productos y añadirlo a la lista de compras, y hacer las mismas comprobaciones sobre el código del producto y el precio.
Gracias por sus valiosos tutoriales y cursos. Son excelentes, y el aporte que le brindan a profesionales y principiantes es importante. Sigan adelante con este gran proyecto!!!