DEV Community

Fran López
Fran López

Posted on • Edited on

Hola, Playwright (II) - Integración CI con Github Actions.

Introducción

En nuestro post anterior vimos como instalar Playwright, definir una prueba de end to end sencilla, y ejecutarla en un navegador local.

Esto está muy bien, podríamos pedirles a nuestros desarrolladores que antes de mezclar a main sus cambios, lanzaran estos tests e2e en sus máquinas y solo subieran los cambios si todo va bien, pero podríamos encontrarnos varios problemas:

  • Primero, que es muy normal que con las prisas a uno se le pase hacerlo y directamente suba los cambios (esto podríamos evitarlo utilizando herramientas como husky, más info en este post).

  • Segundo, si usáramos una tool como Husky que forzara al desarrollador a ejecutar los tests en cada push, estaríamos sobrecargando su máquina y haciendo más lento el proceso, cuando igual lo que queremos es que solo se ejecute en una pull request.

  • Tercero, puede que la máquina del desarrollador no sea el escenario ideal, igual está dentro de una VPN, o tiene acceso a la red... y no queremos que esto afecte a los tests.

¿Te imaginas un proceso en el que, cada vez que crees una Pull Request, automáticamente se inicie una máquina limpia, se ejecuten todos los tests en ella y, si todo sale bien, se permita fusionar la rama sin contratiempos?

Bienvenido al maravilloso mundo de los CI/CD, en este post vamos a ver cómo configurar un pipeline de CI/CD en Github Actions para ejecutar nuestros tests de Playwright en cada Pull Request.

TL;DR;

Partimos del primer post de esta serie (ya tenemos playwright instalado y configurado)

Para poder incluir los tests de e2e en nuestro flujo de integración continua, si usamos Github Actions, tenemos que:

  • Definir un comando en nuestro package.json que ejecute los tests de e2e sin levantar interfaz de usuario.

./package.json

  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives
 --max-warnings 0",
    "preview": "vite preview",
    "format": "prettier --write .",
    "test": "vitest",
    "prepare": "husky || \"No need to install husky\"",
    "tsc-check": "tsc --noEmit",
    "e2e": "playwright test --ui",
+   "ci:e2e": "playwright test"
  },
Enter fullscreen mode Exit fullscreen mode
  • En nuestro flujo de Github Actions añadir una entrada para que los ejecute cuando se lance una Pull Request.

./.github/workflows/ci.yml

name: CI workflow

on: pull_request

jobs:
  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Use Node.js 18.13.0
       uses: actions/setup-node@v2
        with:
          node-version: '18.13.0'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
       run: npm run build

      - name: Check TypeScript Types
        run: npm run tsc-check

      - name: Run E2E tests
        run: npm run ci:e2e
Enter fullscreen mode Exit fullscreen mode

¿Quieres ver cómo funciona esto paso a paso? Sigue leyendo :).

Paso 1: El ejemplo que vamos a usar

Arrancamos del primer post de esta serie, donde instalábamos playwright, hacíamos el setup y escribíamos nuestro primer test de e2e.

Tomamos como punto de partida el primer post de esta serie.

El ejemplo que estamos utilizando como base es el proyecto Open Source Mongo Modeler.

Paso 2: Lanzando test sin interfaz de usuario

En el primer post de esta serie vimos como podemos lanzar los tests de e2e con una interfaz de usuario que nos permite ver en tiempo real cómo se ejecutan los tests, esto está muy bien en tiempo de desarrollo, ya que podemos ver si la interacción con la interfaz es la esperada y podemos incluso depurar e ir atrás y adelante en la línea del tiempo.

Cuando nuestros tests ya están listos, lo que queremos es que se puedan lanzar desde el terminal y nos devuelvan un resultado, abrir la interfaz de usuario en nuestra máquina local podría meter ruido, y... lo más importante, en una máquina virtual o contenedor de un servidor de integración continua no tenemos interfaz de usuario, son máquinas mínimas y tiramos de terminal.

¿Qué podemos hacer? Playwright nos permite lanzar los tests sin interfaz de usuario, para ello vamos a crearnos un comando adicional en nuestro package.json

package.json

  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives
 --max-warnings 0",
    "preview": "vite preview",
    "format": "prettier --write .",
    "test": "vitest",
    "prepare": "husky || \"No need to install husky\"",
    "tsc-check": "tsc --noEmit",
    "e2e": "playwright test --ui",
+   "ci:e2e": "playwright test"
  },
Enter fullscreen mode Exit fullscreen mode

Si lo probamos en nuestro terminal con npm run ci:e2e veremos que se lanzan los tests sin interfaz de usuario.

npm run ci:e2e
Enter fullscreen mode Exit fullscreen mode

Si lanzamos este comando, podemos ver que se lanzan los tests y no se abre ningún navegador.
Al lanzar este comando, vemos como sólo se informa de los resultados vía salida del terminal de texto asociado.

Imagen utilizando el comando y pasando los test e2e sin interfaz de ususario

Ya estamos listos para integrar esto en nuestro flujo de integración continua.

Paso 3: Definiendo un workflow de Github Actions

Github actions funciona de una manera muy sencilla:

  • En la raíz de tu proyecto creas una carpeta .github y dentro otra worfklows, la ruta completa sería la siguiente: .github/workflows

  • Dentro de esa carpeta crearemos ficheros con extensión .yml que definirán los workflows que queremos que se ejecuten en nuestro proyecto.

  • Cuando hagamos push de las acciones, Github las detecta y está listo para ejecutarlas en el momento que le hayamos indicado (por ejemplo, cuando vayamos a hacer una Pull Request).

Lo de forzar a que ciertas carpetas tengan un nombre concreto es una convención de Github, si no lo haces así, no se ejecutarán los workflows, se llama configuración por convención o nomenclatura.

Ya sabemos dónde colocar nuestros workflows, ¿Definimos uno?

  • Seguimos la nomenclatura de yml y las entradas que nos permite Github Actions.

  • Creamos un archivo, por ejemplo, lo podemos llamar ci.yml y lo colocamos en la carpeta .github/workflows

  • En ese archivo le damos un nombre.

  • Después le decimos cuándo se va a lanzar el flujo, en este caso queremos que se lance cuando se haga una pull request.

Como va quedando:

./.github/workflows/ci.yml

name: CI workflow

on: pull_request
Enter fullscreen mode Exit fullscreen mode

Cuidado con las tabulaciones, en yml es importante.

Ahora vamos a definir los jobs que se van a ejecutar, en este caso vamos a lanzar los tests de e2e.

Más información sobre como funcionan las Github Actions en este post.

En este caso, le podemos decir que lance el job de e2e

./.github/workflows/ci.yml

name: CI workflow

on: pull_request

+  e2e-tests:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v2

+      - name: Use Node.js 18.13.0
+       uses: actions/setup-node@v2
+        with:
+          node-version: '18.13.0'
+          cache: 'npm'

+      - name: Install dependencies
+        run: npm ci

+      - name: Build
+       run: npm run build

+      - name: Check TypeScript Types
+        run: npm run tsc-check

+      - name: Run E2E tests
+        run: npm run ci:e2e
Enter fullscreen mode Exit fullscreen mode

Que le estamos diciendo aquí:

  • Tenemos un job llamado e2e-tests.

  • Se va a ejecutar en una máquina con sistema operativo ubuntu.

  • Después vamos a traernos el código de nuestro repositorio.

  • Le decimos que usé la versión de Node.js 18.13.0 (lo añade a la máquina que ejecuta el job).

  • Instalamos las dependencias, fíjate que aquí usamos npm ci en vez de npm install. Esto lo hacemos para que no modifique el fichero package-lock.json.

  • Para asegurarnos que está todo bien construido, lanzamos el comando npm run build.

  • También lanzamos un chequeo de los tipos de TypeScript con npm run tsc-check.

  • Por último, lanzamos los tests de e2e con npm run ci:e2e.

Ya está todo listo para que, cuando hagamos commit y push de este archivo, Github Actions detecte que hay un nuevo workflow y lo ejecute cuando se haga una Pull Request.

A tener en cuenta: en el ejemplo de MongoModeler, el flujo de ci ejecuta dos jobs uno para comprobar que todo está ok y lanzar las pruebas unitarias, y otro para lanzar las e2e, como queda el flujo total:

./.github/workflows/ci.yml

name: CI workflow

on: pull_request

jobs:
  ci:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Use Node.js 18.13.0
        uses: actions/setup-node@v2
        with:
          node-version: '18.13.0'
          cache: 'npm'

      - name: Install front
        run: npm install

      - name: Build
        run: npm run tsc-check

      - name: Tests front
        run: npm test

  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Use Node.js 18.13.0
       uses: actions/setup-node@v2
        with:
          node-version: '18.13.0'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Check TypeScript Types
        run: npm run tsc-check

      - name: Run E2E tests
        run: npm run ci:e2e
Enter fullscreen mode Exit fullscreen mode

Paso 4: Subiendo los cambios

Ahora lo tenemos todo listo, Abrimos una pull request y hacemos commit y push. Nos llevaríamos los cambios a la rama main.

Paso 5: Probando el proceso

Cuando hacemos PR se lanza los jobs que hemos definido anteriormente, vemos como pasan correctamente. Con lo cual le estamos dando robustez a nuestro proyecto. Además, podemos ver detalles de la ejecución del mismo e incluso el terminal de como va el proceso.

imagen de la pr viendo como pasa los jobs

Pincha en datails.

Imagen terminal ejecutando los test

Paso 6: Settings y forzar a que pasen para poder hacer merge

Una funcionalidad interesante que nos ofrece Github es que poder impedir que alguien haga merge si no pasan los e2e test (con la opción de añadir excepciones para por ejemplo perfiles administradores). Para ello, entramos en nuestro portal de Github y nos vamos a los settings del repositorio y elegimos del panel izquierdo Rules / Rules Sets.

Imagen de settings donde se ve Rules y Rulesets

Pincha en "New ruleset"

Imagen New ruleset

Se nos abre un formulario, le damos un nombre a esa regla, le podemos llamar: pass-tests-before-merge y le decimos que la regla está activa.

Imagen donde damos nombre a la regla y la ponemos activa

Después tenemos la opción, por ejemplo un admin se pueda saltar esa regla si queremos.

Imagen Bypass list, role de admin

Ojo con este bypass, sólo es útil para usuarios en concreto y casos puntuales justificados.

Lo siguiente es elegir a qué ramas va a aplicar, en nuestro caso la rama default se llama dev y la main es la que va a producción, así que pedimos que se apliquen en esas dos.

Imagen target branches seleccionando default y main

Y en el apartado de Rules marcamos Require Status check to pass:
Está bien marcar el primer check(Requires branches to up to data before merging), así nos aseguramos que la rama que tenemos tiene la última versión de dev o main.

Imagen Rules marcando las casillas, Require Status check to pass y Requires branches to up to data before merging

Y para los checks, pinchamos en + Add Checks y buscamos el nombre del flujo de github que tenemos definido en nuestra carpeta de workflows (la que está bajo .github/workflows)

Imagen add checks y añadiendo ci es el nombre de nuestro archivo

Ahí vemos que sale vació, pero si tecleamos ci (como se llama nuestro flujo), aparece y podemos seleccionarlo.

Imagen escribiendo ci en el buscador de add checks

Se nos tiene que quedar algo así como:

Imagen de como se queda todo marcado y ci añadido

Para finalizar pulsamos en el botón de create que hay al final del formulario.

Imagen enseñando el boton create al final del formulario para finalizar

Repositorio de ejemplo

Te dejo un enlace al proyecto de github con la configuración completa:

Enlace al repositorio con el proyecto y su configuración completa

Conclusión y siguientes pasos

Ya tienes todo listo para que tus tests e2e con Playwright corran como parte de tu proceso de CI/CD en GitHub Actions. Esto es oro puro para asegurarte de que todo esté bajo control antes de llevar cambios a producción. Ideal para esas aplicaciones que van creciendo y donde cada bug que arreglas tiene el potencial de invitar a un par más a la fiesta 😉. Menos sorpresas, más confianza.

En el próximo post de esta serie, daremos un paso más y aprenderemos cómo escribir tests e2e que interactúan directamente con APIs de servidor. ¡Prepárate para llevar tus pruebas al siguiente nivel! 🚀

Sobre mí

Hola, me llamo Fran y soy desarrollador Front End + QA, si quieres conectar conmigo, te dejo aquí mi perfil de Linked in, ¡encantado de conectar!

Top comments (0)