Playwright: Novedades y otras utilidades
July 7, 2023
¿Qué vamos a ver?
Este artículo sirve como continuación de Playwright: primeros pasos y ejemplos de uso y, vamos a ver funcionalidades de esta herramienta de testing end-to-end, tales como:
-
Nuevo wizard (incluido en la versión 1.32).
-
Cómo generar pruebas con el recorder (plugin).
-
Cómo realizar descargas o subir archivos de forma sencilla.
-
Visual testing.
-
Pruebas de API.
-
Integración con Cucumber.
Ejemplos útiles
Nuevo wizard
Desde la versión 1.32 (y sólo para la opción de Playwright con Node.js) se incluye esta utilidad que nos recuerda mucho al que incluye por defecto Cypress. Para utilizarlo debemos añadir --ui al comando de ejecución de las pruebas, por ejemplo:
npx playwright test userPOM.spec.js --ui
Se abrirá una ventana donde podemos encontrar diferentes utilidades
Filtro
Se incluye la opción de filtrar por resultado de la ejecución o navegador utilizado. También se puede filtrar por los proyectos configurados en el fichero playwright.config.js.
Opciones de ejecución
- Barra de herramientas rápidas, donde encontramos varias opciones:
- Ejecutar todos los tests.
- Parar la ejecución.
- Vigilancia activa: Marcando esta opción, el wizard se mantiene «alerta» a los cambios en el código y, cuando esto ocurra, re-ejecutará el test.
- Colapsar el árbol de tests (disponible en la versión 1.33).
Listado de test disponibles
Desplegable con las pruebas disponibles (en este caso lo ejecutamos a nivel de spec, por lo que muestra los tests disponibles en el fichero). Para cada uno de los tests, tenemos también un submenú con opciones:
- Ejecutar el test.
- Solicita permiso y abre el código de la prueba (sólo si se utiliza VSCode).
- Si se deshabilita la opción de vigilancia en la barra de herramientas rápida, aparece esa opción para cada uno de los tests.
Traza de la ejecución en el tiempo
Vista de la ejecución a lo largo del tiempo. Desplazándonos por esa zona, podemos ver una imagen de la acción en ese momento.
Trazas de la prueba
Solamente aparecen las trazas de los tests que se ejecutan. Se pueden seguir cada una de las acciones realizadas durante la ejecución.
Pestañas de estado
Pulsando sobre cualquier acción del test, tenemos una barra de herramientas con diferentes opciones:
- Recuperar localizadores.
- Estado actual cuando se realiza la acción.
- Estado anterior a realizar la acción.
- Estado posterior a realizar la acción.
Inspeccionar el DOM
Pulsando en este botón, se nos abrirá en el navegador una imagen del DOM en ese momento, donde también podemos inspeccionar el documento, los elementos, la consola, etc.
Imágen del navegador en el momento actual
Barra de información
Diferentes pestañas útiles para revisar durante la ejecución
- Source: Código completo del test seleccionado.
- Console: Logs de la consola para cada acción.
- Network: Logs de la red en cada acción.
- Logs: Trazas de cada acción
Aquí podemos ver un ejemplo de resultado después de ejecutar todos los tests disponibles.
Generar pruebas fácilmente
Gracias al siguiente plugin podemos generar un testing end-to-end directamente «grabando» las acciones manuales que realicemos (aunque también nos ofrece otras opciones interesantes).
Para utilizarlo simplemente entramos en la pestaña de pruebas de la barra lateral y pulsamos en la opción Record new.
Esto nos abrirá un navegador con el que interactuaremos y una spec donde se irá generando el código con nuestras acciones.
Realizar descargas y adjuntar ficheros
Veamos también un par de utilidades que, aunque sean menos habituales, también son importantes en algunos casos, hablamos de realizar descargas y de seleccionar fichero para adjuntar
Realizar descargas
// Se prepara para esperar una descarga
const downloadPromise = page.waitForEvent('download');
// Pulsamos el botón de descarga
await page.getByText('Download file').click();
const download = await downloadPromise;
// Se espera que la descarga termine
console.log(await download.path());
// Se guarda la descarga en la ruta que queramos
await download.saveAs('/path/to/save/download/at.txt');
Adjuntar ficheros
// Se prepara para seleccionar un fichero
const fileChooserPromise = page.waitForEvent('filechooser');
// Pulsamos el botón de cargar el fichero
await page.getByText('Upload file').click();
const fileChooser = await fileChooserPromise;
// En lugar del explorador de archivos para buscar el fichero, directamente se seleccionará el indicado
await fileChooser.setFiles('myfile.pdf');
Visual testing
Siguiendo la documentación oficial, podemos validar que la página contenga imágenes generadas previamente.
import { test, expect } from "@playwright/test";
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('Check image appears in page', async ({ page }) => {
await expect(page).toHaveScreenshot('home.png');
});
La primera vez que ejecutamos el test, fallará porque no existe la imagen con la que comparar. Playwright nos muestra el error y automáticamente nos genera una imagen actual.
Si re-ejecutamos de nuevo el test, esta vez irá todo bien.
Como te podrás imaginar, dentro de el testing end-to-end, Playwright no solo se limita a comparar la página completa, también podemos hacer la comparación de objetos de manera similar de esta forma. Al igual que en el caso anterior, si la imagen no existe, Playwright la genera automáticamente.
import { test, expect } from "@playwright/test";
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('Compare image by locator', async ({ page }) => {
expect(await page.getByRole('link', { name: 'women\'s perfume' }).screenshot()).toMatchSnapshot('women.png');
});
Pruebas de API
Veremos un ejemplo simple de una llamada API haciendo uso de la herramienta y siguiendo la documentación oficial.
import { test, expect } from "@playwright/test";
test('Requests basic', async ({ request }) => {
const people = await request.get(`https://swapi.dev/api/people/1`, {
headers: {
'Content-Type': 'application/json;',
},
});
expect(people.ok()).toBeTruthy();
const response = await people.json();
console.log('response: ' + JSON.stringify(response, null, 2))
expect(people.status()).toBe(200)
expect(response.name).toMatch(/Luke Skywalker/);
});
Cucumber
Por si no era suficiente todo lo anterior, también podemos utilizar Cucumber.
Requisitos previos
Para ello, primero debemos instalar un par de paquetes:
-
npm i @cucumber/cucumber
-
npm i playwright
Feature
Creamos el fichero features/login.feature.
features/login.feature
Feature: Login in perfumes website
@login
Scenario: Check correct login
Given I go to Perfumes WebStore
When I do login
Then I check correct welcome message appears
World (Hooks)
La palabra World describe los pasos donde podemos declarar e invocar objetos y variables que se podrán utilizar globalmente. Es el equivalente a lo que conocemos como Hooks en Java o C#.
// features/support/world.js
const { setWorldConstructor } = require("@cucumber/cucumber");
const playwright = require('playwright');
class CustomWorld {
async openUrl(url) {
const browser = await playwright.chromium.launch({
headless: false,
});
const context = await browser.newContext();
this.page = await context.newPage();
await this.page.goto(url);
}
}
setWorldConstructor(CustomWorld);
Steps
Implementamos el código de cada uno de los pasos.
// features/support/steps.js
const { Given, When, Then } = require("@cucumber/cucumber");
const { expect } = require('@playwright/test');
Given("I go to Perfumes WebStore", { timeout: 60 * 1000 }, async function () {
await this.openUrl('http://localhost:3000');
});
When("I do login", async function () {
await this.page.getByRole('link', { name: 'SIGN IN' }).click();
await this.page.locator('input[name="email"]').fill('test123@test.com');
await this.page.locator('input[name="password"]').fill("admin");
await this.page.getByRole('button', { name: 'Sign in' }).click();
});
Then("I check correct welcome message appears", async function () {
await expect(this.page.getByRole('link', { name: 'EXIT' })).toBeVisible();
await expect(this.page.getByRole('link', { name: 'MY ACCOUNT' })).toBeVisible();
expect((await this.page.content()).includes('Hello John Doe!'));
});
Ejecución
Utilizamos el comando siguiente para filtrar por etiqueta
- npx cucumber-js --tags @login --exit
Qué nos ha parecido
Ventajas
Nos encontramos ante una herramienta en auge y en continua mejora que amplía sus funcionalidades (incluyendo su completa documentación).
Como ya comentamos en el artículo anterior, es una herramienta con una amplia versatilidad que busca simplificar las implementaciones y facilitar la generación de pruebas.
Inconvenientes
Se observa una descompensación entre los diferentes lenguajes. Por citar algunos casos, las aserciones sobre variables, el wizard de ejecución, visual testing, ..., solamente están disponibles para Node.js y no existen para el resto de lenguajes. Ese desajuste es algo que deberían solucionar, ya que puede ser una limitación a la hora de migrar desde otra herramienta.
Conclusiones
Playwright está haciendo un gran trabajo para convertirse en una herramienta de referencia para diferentes tipos de testing end-to-end. Es muy positivo descubrir que está en constante crecimiento y mejora, aunque deberían balancear el esfuerzo para equiparar todos los lenguajes en lugar de limitarse a sólo uno de ellos.
Bibliografía: