"La calidad no es un acto, es un h谩bito"

-- 鉁嶏笍 Arist贸teles

La m铆nima garant铆a de calidad es que algo funcione conforme a lo esperado; es decir que pase un test funcional. Pero desde antiguo se sabe que esto s贸lo es v谩lido si es constante. Para que se convierta en h谩bito nada mejor que hacerlo sencillo, c贸modo y agradable.

Las pruebas E2E pueden, y deben, incorporar comprobaciones funcionales. Hasta ahora hab铆amos visto situaciones muy b谩sica en las que una herramienta libre y gratuita como Puppeteer se defend铆a muy bien.

Pero, cuando probamos funcionalidades complejas se nos complica el uso continuado de la sintaxis as铆ncrona. Incluso con el moderno async/await. Tampoco Puppeteer trae de f谩brica funciones adaptadas al testing. Se le tienen que a帽adir ayudas como la Integraci贸n con Jest, o con otros frameworks de testing como Mocha o Jasmine.

Nada de esto contribuye a integrar el h谩bito de la prueba funcional constante. Y sin ese h谩bito no hay calidad.

Cypress

Cypress es un framework para pruebas funcionales e2e. En este sentido es mucho m谩s potente y c贸modo de utilizar que Puppeteer que no deja de ser un automatizador de navegadores. El fallo es que... Cypress es de pago; pero lo bueno es que tiene una buena parte gratis que es m谩s suficiente para las pruebas funcionales.

Y desde luego es de lo m谩s sencillo, c贸modo y agradable de usar. Ideal para convertirlo en h谩bito de uso.

Instalar Cypress

Instalarlo es trivial. Partimos de una aplicaci贸n Node y agregamos la dependencia. Puedes hacerlo con npm o con yarn y guardarlo como dependencia principal o para desarrollo.

yarn add cypress
npm i --save cypress

Este proceso tarda un poco porque Cypress es mucho m谩s que una librer铆a. Es un test runner que necesita su propio servidor y controlador del navegador. La espera merecer谩 la pena porque adem谩s nos genera una estructura de carpetas para que empecemos con nuestros tests.

As铆 que una vez instalado, se habr谩 creado una carpeta en la ruta cypress\integration. En ella crearemos nuestras especificaciones en ficheros con nombre tipo mi-prueba.spec.js

Test funcionales

Las pruebas funcionales de aplicaciones web, son un tipo e2e que va m谩s all谩 de las superficialidad de surfear con un navegador automatizado. Tambi茅n controlan los navegadores y por supuesto que simulan el comportamiento del usuario en ellos: hacer clic, escribir, desplazarse, etc.

Son consideradas como de integraci贸n porque evidentemente para su ejecuci贸n deben coordinarse distintos servicios. Pero lo diferencial es que:

Las pruebas funcionales aseguran que determinados escenarios realmente funcionen desde el punto de vista de un usuario final.

Probar funcionalidades web con Cypress

Como la mayor铆a de los frameworks de pruebas, Cypress nos ofrece la conocida sintaxis describe it. Se trata de dos funciones que reciben un primer argumento de texto y en el segundo una funci贸n.

Describe it

describe('Funcionalidad que se pretende probar', () => {
  // C贸digo de preparaci贸n y actuaci贸n pruebas
  it('Lo que deber铆a ocurrir', () => {
    // Comprobaci贸n mediante aserciones
  });
});

Es tan importante, o m谩s, prestar atenci贸n al texto que reciben en el primer par谩metro como al c贸digo que se ejecutar谩. Recuerda que el usuario final de este programa eres t煤. Hazte un favor a ti mismo y especifica el texto de la manera m谩s clara posible.

Actuaciones y aserciones

Dentro de las anteriores funciones ir谩 el c贸digo propiamente dicho. Ahora ya usaremos Cypress como una librer铆a mas y habr谩 que familiarizarse con su API. Aunque tu editor puede ayudarte en eso.

/// <reference types="Cypress" />

// Actuaciones como un usuario
cy.visit('https://www.bitademy.com');
// Comprobaciones como un programador
cy.title().should('include', 'bitAdemy');

Ejecutar las pruebas con Cypress

La ejecuci贸n es recomendable lanzarla desde el package.json. Os muestro dos alternativas. Pod茅is instalar Cypress y ejecutar las pruebas desde el mismo repositorio que la aplicaci贸n que est谩is probando. O pod茅is crear una aplicaci贸n de pruebas independiente.

{
  "scripts": {
    "test:e2e": "cypress open",
    "start": "cypress open"
  }
}

En el primer caso, la aplicaci贸n arranca en start y las pruebas en algo tipo test:e2e. Pero si lo hac茅is en un repo aparte... entonces el test se ejecuta directamente desde start.

En el laboratorio he optado por esta aproximaci贸n, un repositorio independiente para la prueba funcional. Adaptadlo a vuestro gusto o situaci贸n particular.

Hola mundo con Cypress

Para que lo veas todo junto te propongo que te crees un fichero cypress\integration\examples\0-hello-world\00-basic.spec.js y escribas esto en 茅l.

/// <reference types="Cypress" />

describe('Visiting the url https://www.bitademy.com', () => {
  it('should have _bitAdemy_ on its title', () => {
    cy.visit('https://www.bitademy.com');
    cy.title().should('include', 'bitAdemy');
  });
});

Si no lo hab铆as hecho antes lanza el runner con el comando cypress open o el script equivalente... y espera que te muestre el panel de administrador con todos los tests disponibles.

Selecciona el 0-hello-world/00-basic.spec y disfruta.

M谩s acciones y comprobaciones

Para familiarizarte un poco m谩s con la sintaxis de Cypress te dejo la versi贸n extendida de este Hola Mundo. Incluye las acciones m谩s comunes como el simular clicks, navegar entre p谩ginas, rellenar formularios... y comprobar contenidos.

De los textos que se incluyen en las funciones se deduce claramente la intenci贸n del desarrollador. Es un caso d贸nde la documentaci贸n forma parte del programa. No es un comentario, es un dato.

Estos tests son de muy alto nivel y normalmente van conducidos por especificaciones behavior driven como esta

FEATURE:     have web site with a title
As a:        visitor
I want to:   view the title of a site
In order to: be more confident

Scenario:
  Given: the url https://www.bitademy.com
  When: I visit it
  Then: should have BitAdemy on its title

Este es el c贸digo que realiza la prueba

describe('Visiting the url https://www.bitademy.com', () => {
  it('should have _bitAdemy_ on its title', () => {
    cy.visit('https://www.bitademy.com');
    cy.title().should('include', 'bitAdemy');
  });
});

const sutUrl = 'https://www.bitademy.com';
describe(`GIVEN: the url ${sutUrl}`, () => {
  context(`WHEN: I visit it`, () => {
    before(() => cy.visit(sutUrl));
    const expected = 'bitAdemy';
    it(`THEN: should have _${expected}_ on its title`, () => {
      cy.title().should('include', expected);
    });
  });
});

Incidiremos m谩s en esta parte en el siguiente tema especialmente dedicado al comportamiento.

Before and after

Si no tienes experiencia previa con frameworks de test, te habr谩 sorprendido la funci贸n before(). Esta y sus hermanas beforeAll, after y afterAll ejecutan la funci贸n que reciben como callback en los momentos adecuados. Sus nombres no dejan lugar a dudas.

Se usan para establecer un escenario en el que se desarrollar谩n las pruebas, definiendo o inicializando variables. No reciben textos informativos. Si quieres dejar rastro tienes que escribir en la consola, en un log...