Ir al contenido

Sharding de Cypress y varios proyectos

Fuera de GitHub Actions, cada cypress run crea su propia ejecución por defecto, así que cuatro máquinas que ejecutan cada una una parte de las specs crean cuatro ejecuciones. En GitHub Actions los jobs de un mismo workflow comparten una ejecución automáticamente (jobs en paralelo). En otros entornos, esta página muestra cómo tener una ejecución para todo un pipeline, y cómo una batería de Cypress reporta en varios proyectos de Probara.

PatrónElígelo cuando
Crea la ejecución, reporta desde cada máquina y ciérralaLa forma habitual: los resultados de cada máquina aparecen en cuanto termina
Archivos de resultados importados por un jobLas máquinas no pueden tener el token, o un solo job debe hacer todo el envío

Cada job que reporta necesita PROBARA_API_TOKEN, un token de aplicación de la tarjeta Cypress en Workspace › Integraciones, configurado como en la sección de tu proveedor de CI.

Cypress no tiene opción --shard: cada máquina ejecuta su propio cypress run, y algo decide qué specs ejecuta. El reporter no depende de qué:

HerramientaQué ejecuta cada máquina
--specLas specs que indicas, como npx cypress run --spec 'cypress/e2e/cart/**'
Cypress Cloud --record --parallelLas specs que le entrega Cypress Cloud
Un plugin como cypress-splitSu parte de las specs; regístralo con cypress-on-fix, porque también registra after:spec y after:run

La ejecución propia de Cypress Cloud (--ci-build-id, --group) es un concepto de Cypress Cloud: el reporter ni la lee ni la necesita. Lo que hace que las máquinas reporten en una sola ejecución de Probara es PROBARA_RUN_ULID, el mismo en todas las máquinas.

Crea la ejecución, reporta desde cada máquina y ciérrala

Sección titulada «Crea la ejecución, reporta desde cada máquina y ciérrala»
  1. Un primer job ejecuta probara run create, que crea una ejecución automatizada vacía e imprime su ULID en stdout.
  2. Cada máquina ejecuta npx cypress run (con su parte de las specs) con ese ULID en PROBARA_RUN_ULID. Un cypress run nunca cierra una ejecución que no creó, así que todas reportan en la ejecución abierta. Probara concilia las máquinas que reportan a la vez: ningún caso se añade dos veces a la ejecución.
  3. Un último job ejecuta probara run close, después de todas las máquinas, incluso si fallaron pruebas.

En una shell, el flujo completo es:

Ventana de terminal
PROBARA_RUN_ULID=$(npx @probara/cli run create)
export PROBARA_RUN_ULID
npx cypress run --spec 'cypress/e2e/cart/**'
npx cypress run --spec 'cypress/e2e/login/**'
npx @probara/cli run close

Asigna el ULID en una línea propia: export PROBARA_RUN_ULID=$(...) ocultaría un fallo al crearla. En CI, los jobs de abajo fijan la versión de la CLI (npx --yes @probara/cli@0.3), que no es una dependencia del reporter; con @probara/cli en tus devDependencies, npx @probara/cli después de npm ci ejecuta la versión del lockfile. probara es la CLI de Probara; usa el mismo token y el mismo proyecto. Las opciones de una ejecución nueva van a run create (--run-name, --environment, --milestone, --plan, --tag…), porque las máquinas reutilizan la ejecución e ignoran sus propias opciones de ejecución.

Cada máquina envía sus resultados cuando termina su propio cypress run, así que la ejecución se completa máquina a máquina, no prueba a prueba.

jobs:
probara-run:
runs-on: ubuntu-latest
outputs:
ulid: ${{ steps.create.outputs.ulid }}
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP
steps:
- uses: actions/setup-node@v5
with:
node-version: 22
- id: create
run: |
ulid=$(npx --yes @probara/cli@0.3 run create)
echo "ulid=$ulid" >> "$GITHUB_OUTPUT"
test:
needs: probara-run
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
spec: ['cypress/e2e/cart/**', 'cypress/e2e/login/**', 'cypress/e2e/search/**']
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 22
- run: npm ci
- run: npx cypress run --spec '${{ matrix.spec }}'
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP
PROBARA_RUN_ULID: ${{ needs.probara-run.outputs.ulid }}
close-probara-run:
needs: [probara-run, test]
if: always() && needs.probara-run.outputs.ulid != ''
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v5
with:
node-version: 22
- run: npx --yes @probara/cli@0.3 run close
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP
PROBARA_RUN_ULID: ${{ needs.probara-run.outputs.ulid }}

Sin el token (un fork), run create no imprime nada y sale con 0, las máquinas no reportan nada, y el job de cierre se omite. Con Cypress Cloud, sustituye la matriz de specs por containers: [1, 2, 3] y ejecuta npx cypress run --record --parallel en cada una: la parte de PROBARA_RUN_ULID no cambia.

Un artefacto dotenv entrega el ULID a cada job posterior:

stages:
- test
create-probara-run:
stage: .pre
image: node:22
variables:
PROBARA_PROJECT: SHOP
rules:
- if: $PROBARA_API_TOKEN
script:
- PROBARA_RUN_ULID=$(npx --yes @probara/cli@0.3 run create)
- echo "PROBARA_RUN_ULID=$PROBARA_RUN_ULID" > probara.env
artifacts:
reports:
dotenv: probara.env
cypress:
stage: test
image: cypress/browsers:latest
parallel:
matrix:
- SPEC: ['cypress/e2e/cart/**', 'cypress/e2e/login/**', 'cypress/e2e/search/**']
variables:
PROBARA_PROJECT: SHOP
script:
- npm ci
- npx cypress run --spec "$SPEC"
close-probara-run:
stage: .post
image: node:22
variables:
PROBARA_PROJECT: SHOP
rules:
- if: $PROBARA_API_TOKEN
when: always
script:
- npx --yes @probara/cli@0.3 run close

.pre y .post son las etapas inicial y final integradas de GitLab; when: always cierra la ejecución incluso después de pruebas fallidas.

Jenkins, CircleCI, Azure Pipelines, Bitbucket Pipelines y Buildkite siguen los mismos tres pasos; sus pipelines completos están en Proveedores de CI.

Alternativa: archivos de resultados importados por un job

Sección titulada «Alternativa: archivos de resultados importados por un job»

Cada máquina se ejecuta con el envío desactivado y escribe cada resultado en un archivo de resultados, que se guarda como artefacto con su carpeta de adjuntos. Un último job, que tiene el token, los descarga todos y los envía.

Un archivo de resultados escrito con el envío desactivado no nombra ninguna ejecución: importado por separado, cada archivo crea su propia ejecución. Para tener una sola, créala primero, importa en ella cada archivo y ciérrala:

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [cart, login, search]
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 22
- run: npm ci
- run: npx cypress run --spec 'cypress/e2e/${{ matrix.shard }}/**'
env:
PROBARA_ENABLED: 'false'
PROBARA_PROJECT: SHOP
PROBARA_RESULTS_FILE: probara-results-${{ matrix.shard }}.json
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: probara-results-${{ matrix.shard }}
path: probara-results-*
retention-days: 1
report:
needs: test
# Forks get no token: there is nothing to send with.
if: ${{ !cancelled() && github.event.pull_request.head.repo.fork != true }}
runs-on: ubuntu-latest
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP
steps:
- uses: actions/setup-node@v5
with:
node-version: 22
- uses: actions/download-artifact@v4
with:
pattern: probara-results-*
merge-multiple: true
- run: |
PROBARA_RUN_ULID=$(npx --yes @probara/cli@0.3 run create)
export PROBARA_RUN_ULID
npx --yes @probara/cli@0.3 import results 'probara-results*.json'
npx --yes @probara/cli@0.3 run close
  • Da a cada máquina su propio nombre de archivo (probara-results-<shard>.json), para que las descargas nunca se sobrescriban entre sí.
  • probara import results envía cada archivo a PROBARA_RUN_ULID, deja esa ejecución abierta (porque la reutilizó) y elimina cada archivo una vez enviado. run close la cierra después.
  • Las capturas y los vídeos se nombran en el archivo por su ruta en la máquina de pruebas, sin copiarse: el job de envío, que nunca los tuvo, no puede enviarlos. Usa la ejecución compartida de arriba cuando te importen.
  • No llega nada a Probara hasta el último job: una máquina que se cae no deja archivo de resultados, y sus resultados faltan.
  • Volver a ejecutar el job de envío ejecuta run create de nuevo: los archivos, descargados otra vez tal como estaban, van a una segunda ejecución con los mismos resultados. Cierra o elimina la que no quieras conservar.

Una ejecución queda abierta hasta que se cierra. Ciérrala a mano, con el ULID del registro del job que la creó:

Ventana de terminal
npx @probara/cli run close --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3
Algo sale malEjecución compartida (crear, máquinas, cerrar)Archivos de resultados, una importación
Una máquina se cae antes de terminar su ejecuciónSus resultados se pierden: se envían cuando termina su cypress runFalta su archivo: no se envía ninguno de sus resultados
Probara no está disponibleEl archivo de resultados de cada máquina guarda lo que no pudo enviar (si se definió)La importación sale con 1 y guarda en cada archivo lo que no pudo enviar
El job de cierre no se ejecutaLa ejecución queda abierta: ciérrala a manoIgual

Una batería de Cypress puede contener las pruebas de varios proyectos de Probara. Indica los demás proyectos en projects, y cada resultado va al proyecto de su caso, en una ejecución de ese proyecto.

reporterOptions: { projectId: 'SHOP', projects: ['WEB'] },

PROBARA_PROJECTS=WEB los indica desde el entorno.

  • Por el proyecto del caso. Un resultado vinculado a WEB-3 va a una ejecución de WEB. Los IDs de cada proyecto indicado también vinculan desde los títulos y salen de la clave, como los del proyecto configurado.
  • Una prueba vinculada a casos de varios proyectos se envía una vez por caso, cada una a su proyecto, con sus archivos subidos a cada resultado.
  • Una prueba sin caso va al proyecto configurado (projectId), donde se asocia por su clave o se crea: solo el proyecto configurado crea casos, bajo suiteUlid.
  • Un ID de un proyecto que no está indicado, en un título, no es un ID: se queda en el título y en la clave, y la prueba va al proyecto configurado. Pasado a probara.id(), es un caso que el reporter no puede enviar a ninguna parte: se omite, y la línea Sending lo cuenta.
[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked); 1 linked only to cases of unlisted projects

Un proyecto de Cypress (el bloque e2e o component de defineConfig) no dice nada sobre a dónde va un resultado: dos configuraciones que reportan en el mismo proyecto de Probara producen las mismas claves, y por tanto los mismos casos.

Cada proyecto indicado tiene su propia ejecución, creada con su primer resultado (un proyecto sin resultados no tiene ejecución), con el mismo nombre, descripción, entorno (por nombre), etiquetas y origen de CI que la del proyecto configurado, y cerrada al final como cualquier ejecución que crea el reporter. La línea Recorded nombra el proyecto cuando hay más de uno: in R-1 of WEB.

El hito, el plan y las configuraciones son entidades de planificación de un proyecto: un nombre que existe en SHOP puede no existir en WEB, donde Probara rechazaría todo el informe. Por eso, como las formas ULID del entorno, el hito y las configuraciones, solo acompañan a la ejecución del proyecto configurado, y una advertencia los nombra. Para dar los suyos a la ejecución de otro proyecto, créala primero y reutilízala:

Ventana de terminal
WEB_RUN=$(npx @probara/cli run create --project WEB --milestone "Web sprint 4")
PROBARA_RUN_ULIDS="WEB=$WEB_RUN" PROBARA_PROJECTS=WEB npx cypress run

run.ulids (PROBARA_RUN_ULIDS=SHOP=<ulid>,WEB=<ulid>) nombra la ejecución que se reutiliza en cada proyecto; la entrada del proyecto configurado cuenta como run.ulid. Una ejecución reutilizada queda abierta salvo que closeRun sea true: ciérrala con probara run close --project WEB --run-ulid <ulid>.

Crea una ejecución por proyecto antes de las máquinas, pásalas todas en PROBARA_RUN_ULIDS y ciérralas después de la última máquina:

Ventana de terminal
SHOP_RUN=$(npx @probara/cli run create)
WEB_RUN=$(npx @probara/cli run create --project WEB)
export PROBARA_PROJECTS=WEB PROBARA_RUN_ULIDS="SHOP=$SHOP_RUN,WEB=$WEB_RUN"
npx cypress run --spec 'cypress/e2e/cart/**'
npx @probara/cli run close --run-ulid "$SHOP_RUN"
npx @probara/cli run close --project WEB --run-ulid "$WEB_RUN"

Cuando se reutiliza la ejecución del proyecto configurado pero un proyecto indicado no tiene ejecución en run.ulids, cada máquina crea su propia ejecución en ese proyecto, y una advertencia lo dice. Un informe fallido solo detiene su proyecto: los demás siguen.

Relacionado: Proveedores de CI · Resultados y reintentos · CLI · Fuente: ci/sharding.md, projects.md