!Bienvenido! El objetivo de este taller es aprender a automatizar pruebas de interfaz gráfica (UI) usando Protractor. Mediante el desarrollo de varios ejercicios prácticos, se abarcará diferentes temas para desarrollar un proyecto de automatización. Durante el desarrollo de los ejercicios, se explicará cómo preparar un proyecto para un proceso de integración continúa con Travis CI, cómo usar SauceLabs como plataforma de pruebas en la nube, el uso de Zalenium para orquestar pruebas (tanto local como en la nube), y el uso de Github y Gitflow para la entrega de un producto de software.
Se asume que la persona tiene conocimientos previos en:
Recursos:
Descripción: Se configurará inicialmente el proyecto con TypeScript y se hará una prueba sobre la página de Google. Adicionalmente se creará la configuración necesaria básica para un repositorio de Github
Nota: Si no tiene conocimiento sobre Github se le recomienda realizar las Guias de Github o el lab de Introduction to Github
Crear una cuenta en Github si no la tiene.
Crear un repositorio en limpio dentro de la página de GitHub con el nombre de “protractor-workshop”
Crear una carpeta en su computador llamada protractor-workshop
y ubicarse en ella en una consola
Seguir las instrucciones para realizar el primer commit (use las que aparece en lá página de github)
echo "# protractor-workshop" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:<su-usuario>/protractor-workshop.git
git push -u origin main
En la configuración del repositorio de GitHub en la opción Branches proteja la rama Master indicando que los PR requieran revisión antes de mergear y que requiera la comprobación del estado antes de hacer merge
Dentro del menú colaboradores agregar a:
Instalar JDK en su equipo si no lo tiene instalado
Instalar NodeJS en su equipo si no lo tiene instalado.
Crear una rama project-setup en el repositorio
git checkout -b project-setup
Crear el archivo .editorconfig a raíz del proyecto con la siguiente información
root = true
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 2
[*.md]
indent_size = 4
trim_trailing_whitespace = false
Instalar la extensión de Visual Studio Code EditorConfig for VS Code
(Generalmente requiere reinicio del IDE)
Ejecutar en una consola npm init
dentro de la ruta donde se encuentra el repositorio y colocar la siguiente información:
Parametro | Valor |
---|---|
Name | workshop-protractor |
Version | [Por Defecto] |
Description | This is a Workshop about Protractor |
Entry Point | [Por Defecto] |
Test Command | protractor dist/protractor/local.config.js |
Git Repository | [Por Defecto] |
Keywords | ui-testing, protractor |
Author | [Su nombre] <[Su correo]> ([su github]) |
License | MIT |
Instalar la dependencia de protractor
npm install --save-dev protractor
Instalar las dependencias de desarrollo de typescript
npm i --save-dev typescript
Instalar los types de NodeJS
npm install --save-dev @types/node
Instalar los types de Jasmines
npm install --save-dev @types/jasminewd2
Crear en la raíz del proyecto la carpeta protractor y dentro de ella el archivo local.config.ts y agregar la siguiente información
import { Config } from 'protractor';
export const config: Config = {
framework: 'jasmine',
specs: [ '../test/google.spec.js' ],
seleniumAddress: 'http://localhost:4444/wd/hub'
};
Actualizar los drivers con el comando
npx webdriver-manager update
En la consola ejecutar
npx webdriver-manager start
Crear la carpeta test en la raíz del proyecto y dentro de la carpeta crear el archivo google.spec.ts
import { browser } from 'protractor';
describe('This is the first example of protractor', () => {
it('should have a title', () => {
browser.driver.get('http://www.google.com');
expect(browser.driver.getTitle()).toEqual('Google');
});
});
Crear el archivo tsconfig.json en la raíz del proyecto con el siguiente contenido
{
"compilerOptions": {
"outDir": "dist",
"sourceMap": true,
"mapRoot": "dist",
"noUnusedLocals": true
}
}
Modificar los scripts del package.json para que tengan el siguiente contenido:
"clean": "rm -rf dist",
"build": "npm run clean && tsc",
"test": "npm run build && protractor dist/protractor/local.config.js"
Ejecutar el comando en una segunda consola npm test
y comprobar que la prueba pasa de forma satisfactoria
Crear el archivo .gitignore en la raíz del proyecto. Ingresar a la página https://www.gitignore.io/ y en el área de texto agregar el sistema operativo, IDE's y NodeJS, ejemplo OSX Node VisualStudioCode. Genere el archivo y cópielo dentro del archivo .gitignore
Agregar al final del .gitignore las siguientes líneas
# Typescript
dist
Crear el archivo LICENSE en la raíz del proyecto con lo especificado en https://en.wikipedia.org/wiki/MIT_License (Tenga en cuanta cambiar el año y el copyright holders)
Crear la carpeta a nivel de raíz llamada .github y dentro de ella crear el archivo CODEOWNERS con el siguiente contenido
* @aperdomob @holgiosalos @veronicatofino @alejagonzalezv @angieVa @kliver98 @danielgalvis98
Realizar un commit donde incluya los 8 archivos modificados con el mensaje “setup protractor configuration” y subir los cambios al repositorio
git add .
git commit -m "setup protractor configuration"
git push origin project-setup
Crear un PR, asignarle los revisores y esperar por la aprobación o comentarios de los revisores. Si no sabe como realizarlo siga las siguientes instrucciones
Una vez aprobado realizar el merge a master seleccionando la opción “squash and merge”
Descripción: Se utilizará el método onPrepare
para configurar la información que debería ser igual en todas las pruebas, adicionalmente se utilizará el beforeEach
para organizar la prueba de forma más legible
Crear la rama improve-test a partir de master
Cambiar el contenido del archivo google.spec.ts por
import { browser } from 'protractor';
describe('Given a SDET learning protractor', () => {
describe('when open Google Page', () => {
beforeEach(() => {
browser.driver.get('http://www.google.com');
});
it('then should have a title', () => {
expect(browser.driver.getTitle()).toEqual('Google');
});
});
});
Ejecutar npm test
y verificar la correcta ejecución de la prueba
Subir los cambios a Github
Crear un PR, asignar los revisores y esperar por la aprobación o comentarios de los revisores.
Una vez aprobado realizar el merge a master seleccionando la opción “squash and merge”
Eliminar la rama una vez mergeada
Descripción: Es necesario poder ver los resultados de una forma entendible en la consola, en esta sesión se configura un reporte de consola.
Instale la dependencia de desarrollo jasmine-spec-reporter
npm install -D jasmine-spec-reporter
Crear la carpeta protractor/helpers y dentro de la carpeta el archivo reporter.ts con el siguiente contenido
import { SpecReporter, StacktraceOption } from 'jasmine-spec-reporter';
export let reporter = () => {
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY,
displayDuration: true
}
}));
};
Modifique el archivo local.config.ts incluyendo el import
del reporter
import { reporter } from './helpers/reporter';
Modificar el protractor/local.config.ts agregando la propiedad onPrepare
con el siguiente contenido:
onPrepare: () => {
reporter();
}
Solicite la revisión de código tal como se hizo en el punto anterior. Dentro de la descripción del PR incluya una imagen con el resultado de la ejecución, así como muestra a continuación
Descripción: En el issue WebDriverJS recomienda dejar de utilizar la implentación propia de promesas personalizadas de Selenium que ha trabajado desde sus inicios, aunque hoy en día aún hay soporte es necesario empezar a trabajar de la forma que recomienda Protractor
Eliminar la propiedad seleniumAddress
del local.config.ts
Termine el proceso del npx webdriver-manager start
(ya no es necesario)
Agregar la propiedad SELENIUM_PROMISE_MANAGER
con el valor false
en el local.config.ts
Modificar el archivo de google.spec.ts para que trabaje con async/await
import { browser } from 'protractor';
describe('Given a SDET learning protractor', () => {
describe('when open Google Page', () => {
beforeEach(async () => {
await browser.driver.get('http://www.google.com');
});
it('then should have a title', async () => {
expect(await browser.driver.getTitle()).toEqual('Google');
});
});
});
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: Muchas veces no contamos con servidores de integración continua que tengan acceso a máquinas con interfaz gráfica. Existen algunos navegadores que tienen versión headless que funcionan sin interfaz gráfica pero se comportan muy similar a los navegadores comunes. En esta sesión vamos a configurar la versión headless de chrome
Duplicar el archivo local.config.ts con el nombre de headless.config.ts
Agregar la propiedad de capabilities en el nuevo archivo con la siguiente información
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: ['--headless', '--disable-gpu']
}
}
Duplicar el script test del package.json con el nombre de test:headless y cambia la ruta de ejecución al archivo headless.conf.js
Cambia el nombre del script test por test:local
Ejecuta tanto el comando npm run test:local
como el npm run test:headless
para comprobar que ejecuta efectivamente
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: La integración continua es una práctica requerida hoy en día, en esta sesión configuraremos travis para ejecutar nuestra integración continua
Crear el archivo .nvmrc en la raíz del proyecto con el contenido v15.3.0
Crear el archivo .travis.yml en la raíz del proyecto
Agregar el siguiente contenido
dist: xenial
addons:
chrome: stable
language: node_js
install:
- npm ci
- npm run webdriver:update
cache:
directories:
- "node_modules"
Habilitar Travis en el repositorio https://docs.travis-ci.com/user/getting-started/
Modificar los scripts de package.json agregando "test": "npm run test:headless"
Agregar el script "webdriver:update"
con el valor "webdriver-manager update --gecko false"
Subir los cambios a github (no cree aún el PR)
Ir a la url de Configuración de Travis
Habilite la configuración GitHub Apps
Cree un PR
Verificar que la ejecución en Travis termine correctamente
Descripción: El análisis de código estático nos ayuda a estandarizar la forma en como escribimos código, en esta sesión configuraremos eslint con airbnb para tener análisis de código estático
Agregar las dependencias de desarrollo eslint, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, eslint-plugin-protractor, y eslint-config-airbnb
Crear el archivo .eslintrc.js en la raíz con la siguientes información
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:protractor/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest"
},
"plugins": [
"@typescript-eslint",
"protractor"
],
"rules": {
"comma-dangle": "off",
"@typescript-eslint/comma-dangle": ["error", "only-multiline"]
}
}
Agregar el script de package.json lint
"lint": "eslint . --ext .ts"
Corregir las reglas de forma automática npm run lint -- --fix
Las reglas que no se puedan corregir automáticamente investigue y corrijalas. Ejecute el comando npm run lint
para verificar que reglas esta rompiendo
Modifique el script de build
del package.json
agregandole al principio npm run lint &&
Solicite la revisión de código tal como se hizo en el punto anterior
NOTA: se recomienda instalar la extensión ESLint
de vs code
Descripción: La depuración nos ayudará a identificar y corregir las parte del código que estén presentando fallas, así como poder tener una mayor entendimiento de las valores de las variables en tiempo de ejecución. Para activar el debugger en vs code
:
Vaya a la vista de Debug
(⇧⌘D - mac / )
Haga click en el ícono del engranaje y seleccione Node.js
. Estor creará el archivo .vscode/launch.json
Reemplace el contenido del archivo por la siguiente información
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug tests",
"program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
"args": ["${workspaceRoot}/dist/protractor/local.config.js"],
"preLaunchTask": "npm: build",
"sourceMaps": true,
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
},
{
"type": "node",
"request": "launch",
"name": "Debug headless tests",
"program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
"args": ["${workspaceRoot}/dist/protractor/headless.config.js"],
"preLaunchTask": "npm: build",
"sourceMaps": true,
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
}
]
}
Compruebe que puede lanzar las pruebas y depurarlas utilzando vs code
Envíe un pull request con una captura de pantalla en la que se identifique fue posible hacer depuración del test google.spec.ts
Solicite la revisión de código tal como se hizo en el punto anterior
Sobre las opciones de depuración de node:
dist
dist
sourceMap
Descripción: Los css selector son los selectores más utilizados por los desarrolladores, tener un buen dominio de ellos facilita la automatización de pruebas. En esta sesión se implementará un primer caso de pruebas con css selectores
Crear el archivo buy-tshirt.spec.ts dentro de la carpeta test
Escribir dentro del archivo el siguiente contenido
import { $, browser } from 'protractor';
describe('Buy a t-shirt', () => {
beforeEach(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000;
});
it('then should be bought a t-shirt', async () => {
await browser.get('http://automationpractice.com/');
await(browser.sleep(10000));
await $('#block_top_menu > ul > li:nth-child(3) > a').click();
await(browser.sleep(3000));
await $('#center_column a.button.ajax_add_to_cart_button.btn.btn-default').click();
await(browser.sleep(3000));
await $('[style*="display: block;"] .button-container > a').click();
await(browser.sleep(3000));
await $('.cart_navigation span').click();
await(browser.sleep(3000));
await $('#email').sendKeys('aperdomobo@gmail.com');
await $('#passwd').sendKeys('WorkshopProtractor');
await $('#SubmitLogin > span').click();
await(browser.sleep(3000));
await $('#center_column > form > p > button > span').click();
await(browser.sleep(3000));
await $('#cgv').click();
await(browser.sleep(3000));
await $('#form > p > button > span').click();
await(browser.sleep(3000));
await $('#HOOK_PAYMENT > div:nth-child(1) > div > p > a').click();
await(browser.sleep(3000));
await $('#cart_navigation > button > span').click();
await(browser.sleep(3000));
await expect($('#center_column > div > p > strong').getText())
.toBe('Your order on My Store is complete.');
});
});
Modifique los archivos de configuración de protractor cambiando
specs: ['../test/**/*.spec.js']
y
getPageTimeout: 1000
Ejecute las pruebas tanto con interfaz gráfica como en modo headless. Si alguna prueba falla modificarla utilizando css locators o los tiempos hasta que logre funcionar
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: El page object model es el patrón por defecto que se utiliza para la mantenibilidad de las pruebas, conocer cómo implementar este patrón le ahorrará muchas horas de reproceso en el futuro. En esta sesión se hará la primera implementación del patrón Page Object Model (POM)
Crear la carpeta src/page desde la raíz del proyecto
Crear el archivo src/page/menu-content.page.ts con el siguiente contenido
import { $, ElementFinder } from 'protractor';
export class MenuContentPage {
private tShirtMenu: ElementFinder;
constructor () {
this.tShirtMenu = $('#block_top_menu > ul > li:nth-child(3) > a');
}
public async goToTShirtMenu(): Promise<void> {
await this.tShirtMenu.click();
}
}
Crear el archivo src/page/index.ts con el siguiente contenido
export { MenuContentPage } from './menu-content.page';
Modificar el archivo buy-tshirt.spec.ts de la siguiente forma
Importar la dependencia del page object despues del import de protractor
import { browser } from 'protractor';
import { MenuContentPage } from '../src/page';
Creando una instancia del objeto MenuContentPage
describe('Buy a t-shirt', () => {
const menuContentPage: MenuContentPage = new MenuContentPage();
Modificando el locator que le da clic en el menú de t-shirt
await browser.get('http://automationpractice.com/');
await(browser.sleep(3000));
await menuContentPage.goToTShirtMenu();
Realice el resto de page object y remplacelo en la prueba, los nombres de los page object son: address-step.page.ts, bank-payment.page.ts, order-summary.page.ts, payment-step.page.ts, product-added-modal.page.ts, product-list.page.ts, shipping-step.page.ts, sign-in-step.page.ts, summary-step.page.ts
Ejecute las pruebas tanto con interfaz gráfica como en modo headless. Si alguna prueba falla modificarla utilizando css locators o los tiempos hasta que logre funcionar
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: Las esperas en selenium son los tiempos que se esperará para realizar algunas acciones, conocerlos y saber cómo utilizarlos nos disminuirá la fragilidad de las pruebas y adicionalmente nos ayudará a reducir los tiempos de ejecución.
Cambia el valor del getPageTimeout
por 30000
en los archivos de configuración de protractor
Elimina el sleep
de 10000
Ejecutar las pruebas y verifica que aun sigan funcionando
Agregar el tiempo de espera de Jasmine dentro de los archivos de configuración como muestra la siguiente imagen
jasmineNodeOpts: {
defaultTimeoutInterval: 120000
}
Eliminar el beforeEach
de la prueba
Ejecute las pruebas tanto con interfaz gráfica como en modo headless. Si alguna prueba falla modificarla utilizando css locators o los tiempos hasta que logre funcionar
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: Una espera implícita es una espera global que se tiene para cada elemento de la página. En esta sesión veremos cómo tenerla configurada nos ayudará a reducir la cantidad de sleeps de la prueba
Agregar dentro del onPrepare de los archivos de config la línea
browser.manage().timeouts().implicitlyWait(3000);
Quitar todos los sleeps de la prueba
Ejecute las pruebas tanto con interfaz gráfica como en modo headless. Si alguna prueba falla modificarla utilizando css locators o los tiempos hasta que logre funcionar
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: Las esperas explícitas es la más recomendada, ya que nos permite hacer esperas puntuales sobre algunos elementos y no sobre todos. En esta sesión desactivaremos las esperas implícitas y activaremos las explícitas donde sea necesario
Modificar los archivos de configuración de tal forma que desactive las esperas implicitas
browser.manage().timeouts().implicitlyWait(0)
Ejecute la prueba e identifique en qué partes la prueba falla
Utiliza esperas explícitas para solucionar las fallas de la prueba. busque apoyo de browser y ExpectedConditions
Ejecute las pruebas tanto con interfaz gráfica como en modo headless. Si alguna prueba falla modificarla utilizando css locators o los tiempos hasta que logre funcionar
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: En esta sesión usted hará la propuesta de que locators deberían ser utilizados en la prueba que se está implementado.
Descripción: Por legibilidad es bueno tener sesionados cada uno de los pasos de las pruebas en diferentes describes, en esta sesión usted aprenderá cómo hacerlo
it
de validación)Descripción: agregaremos un reporte visual a nuestro proyecto de tal forma que tenga un reporte html de la ejecución de las pruebas
Descripción: Las popups que muestra chrome cuando se está ejecutando por selenium son molestas y pueden causar fragilidad en las pruebas, en esta sesión se enseñará a desactivarlas por medio de las capabilities.
Modificar la configuración local de protractor agregando capabilities para chrome para evitar mostrar algunas ventanas emergente en la ejecución
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: ['--disable-popup-blocking', '--no-default-browser-check', '--window-size=800,600'],
prefs: { credentials_enable_service: false }
}
},
Tomar una foto de que el test se ejecuta sin las ventanas emergentes y colocarla en la descripción del PR
Ejecute las pruebas tanto con interfaz gráfica como en modo headless. Si alguna prueba falla modificarla utilizando css locators o los tiempos hasta que logre funcionar
Solicite la revisión de código tal como se hizo en el punto anterior
Descripción: En muchas ocasiones tenemos que obtener un locator para posteriormente poder hacer una acción sobre un hermano o alguno que no esté directamente relacionado, en esta sesión trabajaremos con la anidación de locators y métodos de búsqueda para poder conseguir relacionar dos locators
products
el cual obtendrá todos los productosfindByProduct
el cual debe retornar toda la caja del producto con el nombre específico. Utilice $
para obtener elementos internos del locator, filter
para filtrar la lista y first
para obtener el primer elemento. Revise la API de protractor por si tiene alguna dudaselectProduct
que reciba el nombre del producto y le da clic en la imagenDescripción: esta sesión automatizaremos otra página diferente, y su misión es seleccionar los mejores locators posibles de tal forma que el page object sea lo más reutilizable posible
Crear el archivo personal-information.page.ts en la carpeta src/page
Crear el archivo locators.spec.ts en la carpeta de test, dentro de este archivo se navegará a https://www.tutorialspoint.com/selenium/selenium_automation_practice.htm y ejecutará el siguiente método que debe llenar el formulario con la información que se indica y dar clic en el botón Button (Evitar el uso de css locators)
await personalInformationPage.fillForm({
firstName: 'Alejandro',
lastName: 'Perdomo',
sex: 'Male',
experience: 7,
profession: ['Automation Tester'],
tools: ['Selenium Webdriver'],
continent: 'South America',
commands: [
'Browser Commands',
'Navigation Commands',
'Switch Commands',
'Wait Commands',
'WebElement Commands']
});
Realizar una comprobación del título "Practice Automation Form"
Descripción: Selenium tiene algunas limiaciones y por tanto en ocasiones nos toca ejecutar código directamente en javascript para poder hacer una acción que necesitamos, en este sesión cambiaremos una propiedad de un locator por medio de javascript ya que selenium no es capaz de soportarlo nativamente.
Cree el archivo page i-frame.page.ts el cual contendrá un método para modificar la altura de un IFrame y otro para obtener su altura
import { $, browser, ElementFinder, promise } from 'protractor';
...
public setFormFrameHeight(height: number): promise.Promise<void> {
return browser.executeScript(`arguments[0].height = ${height};`, this.iframe1);
}
Descripción: Los IFrames aunque ya están mandados a recoger, en ocasiones no los encontramos en algunas páginas, y no está de más saber cómo trabajar con ellos cuando nos los encontremos. En esta sesión entraremos a un iframe, haremos acciones sobre el, saldremos de él y haremos otras acciones sobre la página principal
Modificar el page i-frame.page.ts de tal forma que publique:
public async switchToFrame(): Promise<void> {
await browser.switchTo().frame(this.frame.getWebElement());
}
public async switchToMainPage(): Promise<void> {
await browser.switchTo().defaultContent();
}
Modificar la prueba i-frame.spec.ts de tal forma que verifique el título principal
Modificar la prueba i-frame.spec.ts de tal forma que se cambie al iframe 1 y verifique el título
Modificar la prueba i-frame.spec.ts de tal forma que se cambie al contexto principal y verifique nuevamente el título
Descripción: En esta sesión se automatizará una prueba donde se deba subir un archivo.
fillForm
ahora no haga clic en el botón y cree otro método submit que llene el formulario y haga clic en el botónDescripción: En esta sesión se automatizará una prueba donde se deba descargar un archivo
downloadFile
dentro del JSON llame al método privado download
de ese mismo pageobjectdownload
obtendrá el link del enlace "Test File to Download" y se lo pasará al método downloadFile
que recibe dos parametros de entrada el link de descarga y el nombre del archivo con que se quiere guardarCrear la carpeta service dentro de src y crear dentro un archivo llamado download.service.ts que tendrá dos métodos públicos
public async downloadFile(link: string, filename): Promise<void>
Este método obtendrá la información del link y lo guardará en una carpeta temp a nivel raíz del proyecto con el nombre indicado
public readFileFromTemp(filename: string): Buffer
Recibirá el nombre del archivo y devolverá el buffer que contiene la información del archivo
Descripción: Ejecutar en modo headless no siempre es la mejor opción, existen herramientas de pago como Saucelabs que nos provisionan diferentes sistemas operativos y diferentes navegadores, en esta sesión configuraremos saucelabs para ejecutar nuestras pruebas.
Ya que nuestras pruebas se ejecutarán en un servidor de integración sin interfaz gráfica, debemos utilizar servicios externos para la ejecución en browsers reales. En este caso utilizaremos saucelabs.
Crear una cuenta en SauceLabs
Una vez creada la cuenta, ir a la opción de User Settings
Ir a la sección de Access Key y dar click en show. Esto pedirá el password para mostrar el access key. Una vez lo acceda, cópielo al portapapeles y guárdelo en un lugar seguro
Adicione al archivo package.json el script test:saucelabs
y haga que este se corra cuando se ejecute el script de test
"test:saucelabs": "npm run build && protractor dist/protractor/saucelabs.config.js",
"test": "npm run test:saucelabs"
Duplique el archivo protractor/local.config.ts con el nombre protractor/saucelabs.config.ts
Adicione las siguientes propiedades protractor/saucelabs.config.ts:
sauceUser
: tendrá el valor del user name de saucelabs (se obtendrá por variable de ambiente)sauceKey
: tendrá el valor del key de saucelabs copiado en el punto 3 (se obtendrá por variable de ambiente)Capabilities.name
: nombre de la ejecución del job en saucelabs// ...
export let config: Config = {
// ...
sauceUser: process.env.SAUCE_USERNAME,
sauceKey: process.env.SAUCE_ACCESS_KEY
};
// ...
capabilities: {
name: 'UI Workshop',
browserName: 'chrome',
chromeOptions: {
args: ['--disable-popup-blocking', '--no-default-browser-check', '--window-size=800,600'],
prefs: { credentials_enable_service: false }
}
},
// ...
Una vez configurado esto, en la consola asigne los valores para SAUCE_USERNAME
y SAUCE_ACCESS_KEY
, con los valores del registro en saucelabs
export SAUCE_USERNAME='sauce-username'
export SAUCE_ACCESS_KEY='sauce-keu'
Ejecute la prueba npm test
Esto lanzará la ejecución directamente en saucelabs y se puede visualizar de la siguiente forma: http://recordit.co/pIAXMQShQJ
Para que travis tome correctamente el SAUCE_ACCESS_KEY
se debe configurar la variable de forma encriptada
travis encrypt SAUCE_USERNAME=el-usuario --add --com
travis encrypt SAUCE_ACCESS_KEY=el-key --add --com
Nota 1: Si recibe un mensaje de error similar a repository not known to https://api.travis-ci.org/: owner/repo
Inicie sesión usando el comando travis login --com
, se le solicitara ingresar su usuario y contraseña de Travis
Nota 2: Si no desea instalar el cliente de travis puede utilizar docker de la siguiente forma:
docker run -v $(pwd):/usr/src/app -it ruby /bin/bash
gem install travis -v 1.8.9 --no-rdoc --no-ri
echo 'y' | travis -v
cd /usr/src/app
travis encrypt SAUCE_USERNAME=el-usuario --add --com
travis encrypt SAUCE_ACCESS_KEY=el-key --add --com
SAUCE_USERNAME
y SAUCE_ACCESS_KEY
Descripción: Nuestros productos generalmente deben ser verificados en más de un navegador, por tanto es importante saber cómo ejecutar nuestras pruebas en varios navegadores.
Necesitaremos editar el archivo protractor/saucelabs.config.ts, con los siguientes valoresCambiar capabilities por multiCapabilities
multiCapabilities
: contiene la configuración de varios navegadores en un mismo config fileimport { browser, Config } from 'protractor';
import { reporter } from './helpers/reporter';
const firefoxConfig = {
browserName: 'firefox',
platform: 'linux',
name: 'firefox-tests',
shardTestFiles: true,
maxInstances: 1
};
const chromeConfig = {
browserName: 'chrome',
name: 'chrome-tests',
shardTestFiles: true,
maxInstances: 1
};
const multiCapabilities = [chromeConfig, firefoxConfig];
export let config: Config = {
multiCapabilities,
// ...
};
Ejecute las pruebas y en el PR suba la imagen que muestre que esta corriendo en diferentes navegadores
Descripción: En ocasiones requerimos ejecutar nuestras pruebas en nuestro ambiente local o en un servidor de integración continua pero no tenemos los recursos suficientes para pagar todas las ejecuiones que se requieren en servicios como Saucelabs, o simplemente no queremos instalar ciertos navegadores en nuestro equipo ya que nos puede afectar nuestro ambiente de trabajo. Zalenium nos permite ejecutar nuestras pruebas dentro de containers si cumplen ciertos requerimientos y el resto mandarlo a Saucelabs de esa forma no tenemos que hacer configuraciones adicionales y tampoco incurrir a facturas muy grandes
Descargue la imagen de docker elgalu/selenium
docker pull elgalu/selenium
Descargue la imagen de zalenium
docker pull dosel/zalenium
Nota 1: Si recibe un mensaje de error similar a Error response from daemon: Get https://registry-1.docker.io/v2/: unauthorized:incorrect username or password
Inicie sesión usando el comando echo "YOUR_DOCKER_PASSWORD" | docker login --username YOUR_DOCKER_USERNAME --password-stdin
Ejecute el contenedor de zalenium
docker run --rm -ti --name zalenium -p 4444:4444 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp/videos:/home/seluser/videos \
--privileged dosel/zalenium start
Duplicar el archivo de saucelabs.config.ts y llamarlo zalenium.config.ts
Configure el archivo de zalenium para que apunte al servidor de Grid de Zalenium
seleniumAddress: 'http://localhost:4444/wd/hub'
Abrá la página http://localhost:4444/grid/admin/live
Remueva del package.json la instrucción del --gecko false
en el script del postinstall
Agregue el script de test:zalenium
en el package.json
Ejecute el comando npx webdriver-manager update
Ejecute las pruebas con npm run test:zalenium
y vea como en la página de live
se refresca la ejecución de las pruebas
Abrá la página http://localhost:4444/dashboard
y tome un screenshot del resultado de las pruebas y lo adjunta al PR