Black Friday en 15 días: ¿podrán pagar sus clientes? -25 % el primer año y puesta en marcha gratuita, hasta el 30 de noviembreVer la oferta →

Integración

Probar el proceso de pago en cada despliegue con GitHub Actions

Después de cada puesta en producción, un navegador real repite el camino del cliente hasta la página de pago. Si un paso se rompe, el job se pone en rojo.

Obtener mi clave de APIContrato OpenAPI

Documento completo, sin autenticación, listo para su generador de clientes.

El workflow completo, listo para copiar

Aquí tiene el archivo entero. El job deploy pone su sitio en producción. Después, el job tunnel-paiement pide a Pathly que repita su Flow en un navegador real, desde el producto hasta la página de pago. Si un paso se rompe, el job se pone en rojo.

La línea needs: deploy fija el orden. El job tunnel-paiement solo arranca si el despliegue ha terminado bien. El Flow prueba así la versión que acaba de llegar a producción, no la anterior.

timeout_sec da a la Action el tiempo de esperar el veredicto. Su valor por defecto es de 120 segundos. Un proceso de pago recorre varias páginas, por eso el workflow deja cinco minutos. Pasado ese plazo, la Action se detiene y el job falla.

Le quedan tres cosas por preparar: el Flow, la clave de API y los dos ajustes del repositorio. Las secciones siguientes las detallan en ese orden.

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      # Sustituya por su comando de despliegue
      - run: ./scripts/deploy.sh

  tunnel-paiement:
    name: Proceso de pago
    needs: deploy
    runs-on: ubuntu-latest
    steps:
      - name: Pathly Flow
        uses: pathlyhq/pathly-action@v1
        with:
          api_token: ${{ secrets.PATHLY_API_TOKEN }}
          operation: run-scenario
          scenario_id: ${{ vars.PATHLY_CHECKOUT_SCENARIO_ID }}
          timeout_sec: "300"

Por qué probar después de la puesta en producción

Sus tests previos a la fusión comprueban el código. No ven la producción: sus variables de entorno, su caché, su proveedor de pago, sus scripts de terceros. Una puesta en producción puede romper el proceso de pago con todos los tests en verde.

El caso típico: el Ping está en verde, el Flow está en rojo. El sitio responde 200 y la página de inicio se muestra, pero el botón Comprar ya no hace nada. Un control de disponibilidad no lo ve. Un navegador que hace clic, sí.

Este control no sustituye sus tests previos a la fusión. Se añade después de ellos. Los tests dicen que el código es correcto. El Flow dice que un cliente todavía puede llegar a la página de pago, en el sitio real, pocos minutos después del despliegue.

Crear el Flow del proceso de pago

El Flow se crea en la consola, con el grabador, sin escribir código. Usted abre su tienda en el grabador y recorre el camino de un cliente. Pathly guarda cada clic como un paso.

Pasos típicos: abrir una ficha de producto, añadir el producto al carrito, abrir el carrito, continuar hasta la página de pago. Añada una verificación al final, por ejemplo un texto que solo muestra la página de pago.

El Flow se detiene en la página de pago. No paga nada y solo introduce valores de prueba. Elija un producto siempre disponible, reservado para este control si puede.

Una vez guardado el Flow, anote su identificador. Es un UUID, visible en la dirección de la página del Flow en la consola. Lo guardará en una variable del repositorio en el paso siguiente.

Una clave de API con dos alcances

Cree una clave de API en la consola, en Ajustes → Claves de API. Empieza por sp_… y su secreto solo se muestra una vez. Dele únicamente dos alcances: runs:trigger para lanzar un run, runs:read para leer su resultado.

Cree una clave por repositorio. Si un repositorio se filtra, usted revoca su clave sin tocar las demás. Con estos dos alcances, una clave robada no puede crear, modificar ni eliminar un Flow.

En GitHub, abra Settings → Secrets and variables → Actions. Guarde la clave en el secreto PATHLY_API_TOKEN. Guarde el identificador del Flow en la variable PATHLY_CHECKOUT_SCENARIO_ID. El identificador no es un secreto: basta una variable, y sigue siendo legible en los registros.

Antes de conectar el Flow, haga un primer control con operation: ping. Esta operación solo comprueba que la API reconoce la clave. No lanza ningún run.

Primer control: la clave se reconoce

- name: Pathly ping
  uses: pathlyhq/pathly-action@v1
  with:
    api_token: ${{ secrets.PATHLY_API_TOKEN }}
    operation: ping

run-scenario o assert-scenario

La Action ofrece dos operaciones que se parecen. Después de un despliegue, la que usted necesita es run-scenario. Lanza un run nuevo con POST /v1/scenarios/{id}/run y luego consulta GET /v1/runs/{id} hasta obtener un estado final. El resultado describe así la versión que acaba de entregar.

assert-scenario no lanza nada. Lee el último resultado conocido del Flow, con el alcance scenarios:read. Ese resultado puede ser anterior al despliegue: el job estaría en verde sin que la nueva versión se haya probado nunca.

assert-scenario conserva su interés en otros casos. No consume ninguna ejecución y responde al instante. Sirve para un control antes de un paso arriesgado, cuando el Flow ya se ejecuta a intervalos regulares. No sirve justo después de una puesta en producción.

assert-scenario: lee el último resultado, no lanza nada

- name: Pathly assert
  uses: pathlyhq/pathly-action@v1
  with:
    api_token: ${{ secrets.PATHLY_API_TOKEN }}
    operation: assert-scenario
    scenario_id: ${{ vars.PATHLY_CHECKOUT_SCENARIO_ID }}

Leer un fallo

La Action declara tres salidas: run_id, run_status y ok. run_status vale ok, fail o error. Cuando el run no es ok, el job falla. Su registro muestra entonces el identificador del run, su estado y su mensaje: empiece por ahí.

fail: un paso o una verificación del Flow falla. El sitio responde, pero el camino del cliente está roto. Es el caso que este control debe atrapar: un botón que ya no reacciona, un carrito vacío, una página de pago que nunca se alcanza.

error: el run no llegó al final por un error de red o del navegador. Sitio inaccesible, tiempo de conexión agotado, navegador caído. Un sitio que ya no responde en absoluto tras la puesta en producción da por tanto error, no fail.

Para el detalle, llame a GET https://api.pathlyhq.com/v1/runs/{id} con la misma clave. La respuesta devuelve status, message y, cuando existe una captura, screenshotUrl. Es un enlace firmado a la captura del paso que falla, válido durante 15 minutos. screenshotExpiresAt indica la hora de caducidad. Vuelva a llamar a la ruta para obtener un enlace nuevo.

El detalle de un run y el enlace de su captura

# RUN_ID: el identificador que muestra el registro del job
curl -sS https://api.pathlyhq.com/v1/runs/$RUN_ID \
  -H "Authorization: Bearer $PATHLY_API_TOKEN" \
  | jq '{status, message, screenshotUrl, screenshotExpiresAt}'

El último run del Flow, sin conocer su identificador

curl -sS "https://api.pathlyhq.com/v1/runs?scenarioId=$PATHLY_CHECKOUT_SCENARIO_ID&limit=1" \
  -H "Authorization: Bearer $PATHLY_API_TOKEN" \
  | jq '.items[0] | {id, status, message}'

Reaccionar: vuelta atrás y alerta

Un job en rojo no sirve de nada si nadie lo mira. Añada un job rollback con needs: tunnel-paiement e if: failure(). Solo se ejecuta si el control ha fallado, y vuelve a poner la versión anterior en producción.

failure() es verdadera en cuanto falla un job anterior, incluido el despliegue. La condición needs.tunnel-paiement.result == 'failure' reserva la vuelta atrás al fallo del control de Pathly únicamente.

El job queda en rojo tanto con fail como con error, pero la respuesta es distinta. Con fail, el camino del cliente está roto: vuelva atrás. Con error, relance el job una vez. Si el error se repite, vuelva atrás también.

Avise también al equipo. Un webhook suscrito al evento run.failed envía el fallo a su herramienta de alertas. Créelo en la consola, o por la API con una clave que tenga alerting:write, distinta de la clave de la CI. Los canales de terceros (Slack, Teams, webhooks) forman parte de los planes de pago.

Job rollback, a continuación de los otros dos

  rollback:
    needs: tunnel-paiement
    if: failure() && needs.tunnel-paiement.result == 'failure'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      # Sustituya por su comando de vuelta atrás
      - run: ./scripts/rollback.sh

Webhook run.failed hacia su herramienta de alertas

# PATHLY_ALERTING_TOKEN: una clave con alerting:write, no la de la CI
curl -sS -X POST https://api.pathlyhq.com/v1/webhooks \
  -H "Authorization: Bearer $PATHLY_ALERTING_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.example.com/hooks/pathly",
    "events": ["run.failed"]
  }'

Ir más lejos

Varias tiendas: cree un Flow por tienda y recorra sus identificadores con strategy.matrix. Cada tienda tiene su job y su veredicto. Con fail-fast: false, el fallo de una tienda no cancela el control de las demás.

Ventana de mantenimiento: si el despliegue corta el sitio un instante, abra una ventana antes de desplegar. Silencia las alertas de la supervisión habitual durante ese intervalo. La Action no tiene una operación dedicada: llame a la API /v1/maintenance-windows con otra clave, que tenga maintenance:write.

ensure-scenario crea el Ping del sitio si no existe. Si ya existe, lo deja tal cual, sin modificarlo. Lo encuentra por su nombre: relanzar el workflow no crea duplicados. Esta operación exige el alcance scenarios:write, por tanto una clave distinta de la del control.

Dos despliegues seguidos: sin protección, dos controles se cruzan y el segundo puede probar una versión entregada a medias. Un bloque concurrency hace esperar a la segunda ejecución del workflow hasta que termine la primera, control incluido.

Varias tiendas con strategy.matrix

  tunnel-paiement:
    needs: deploy
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        scenario_id:
          - ${{ vars.PATHLY_CHECKOUT_FR_SCENARIO_ID }}
          - ${{ vars.PATHLY_CHECKOUT_DE_SCENARIO_ID }}
    steps:
      - name: Pathly Flow
        uses: pathlyhq/pathly-action@v1
        with:
          api_token: ${{ secrets.PATHLY_API_TOKEN }}
          operation: run-scenario
          scenario_id: ${{ matrix.scenario_id }}
          timeout_sec: "300"

Ventana de mantenimiento de quince minutos, antes del despliegue

START=$(date -u +%Y-%m-%dT%H:%M:%SZ)
END=$(date -u -d "+15 minutes" +%Y-%m-%dT%H:%M:%SZ)

curl -sS -X POST https://api.pathlyhq.com/v1/maintenance-windows \
  -H "Authorization: Bearer $PATHLY_MAINTENANCE_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"startsAt\": \"$START\", \"endsAt\": \"$END\"}"

ensure-scenario: el Ping del sitio, sin duplicados

- name: Pathly Ping
  uses: pathlyhq/pathly-action@v1
  with:
    api_token: ${{ secrets.PATHLY_SETUP_TOKEN }}
    operation: ensure-scenario
    scenario_json: |
      {
        "name": "Home",
        "url": "https://www.example.com/",
        "intervalSec": 300
      }

concurrency: un despliegue a la vez

concurrency:
  group: deploy-production
  cancel-in-progress: false

Trampas habituales

La CDN sigue sirviendo la versión antigua. El Flow prueba entonces el sitio anterior y el job queda en verde por error. Purgue la caché en el job deploy y espere a que termine la purga antes de dar paso al control.

Una protección antibots o un CAPTCHA bloquea el navegador de Pathly. El Flow falla mientras sus clientes pasan. Un CAPTCHA detiene este navegador como a cualquier robot: manténgalo fuera de las páginas que recorre el Flow, o prevea una regla para este tráfico de prueba en su cortafuegos de aplicación.

El producto de prueba está agotado. El botón de añadir al carrito desaparece y el Flow se pone en rojo sin que el código haya cambiado. Reserve para la prueba un producto siempre disponible.

La cuota. Un run lanzado por la CI cuenta en la cuota de ejecuciones de su plan, como los demás. Con la cuota alcanzada y sin paquete de ejecuciones, el run termina en fail con un mensaje de cuota y el job se pone en rojo. Lea el mensaje antes de volver atrás: aquí el sitio no tiene la culpa.