Ir al contenido

Resultados, estados y reintentos en Cypress

Cada cypress run reporta en una ejecución de Probara: una ejecución automatizada nueva por defecto, cerrada al final, o una existente. Cada intento de cada prueba es un resultado en ella, con el veredicto del propio Cypress. Esta página cubre la ejecución, los estados, los reintentos, qué pasa cuando los resultados no se pueden enviar y quién recibe los fallos.

El plugin crea la ejecución, envía a ella cada resultado de cada spec y la cierra cuando Cypress termina la ejecución. Estas opciones describen la ejecución que crea:

cypress.config.js
reporterOptions: {
projectId: 'SHOP',
run: {
name: 'Nightly regression',
description: 'Every night on main, against staging.',
environment: 'staging',
milestone: 'Sprint 12',
plan: 'PLAN-2',
configurations: [
{ group: 'Browser', name: 'Chrome' },
{ group: 'OS', name: 'Linux' },
],
tags: ['nightly', 'e2e'],
},
},
OpciónVariableQué define
run.namePROBARA_RUN_NAMEEl nombre. Por defecto: el nombre del build de CI (CI #42), si no Automated run <date> <time> UTC
run.descriptionPROBARA_RUN_DESCRIPTIONPara qué es la ejecución
run.environmentPROBARA_ENVIRONMENTEl entorno, por nombre: se crea en el proyecto si ninguno tiene ese nombre
run.milestonePROBARA_MILESTONEEl hito, por ID visible (M-3) o nombre exacto
run.planPROBARA_PLANEl plan de pruebas, por ID visible (PLAN-2) o nombre: la ejecución empieza con los casos del plan
run.configurationsPROBARA_CONFIGURATIONSValores de configuración por grupo y nombre (Browser=Chrome,OS=Linux), cada grupo una vez
run.tagsPROBARA_RUN_TAGSEtiquetas (nightly,e2e)

La misma ejecución desde el entorno de un paso de CI, con el proyecto en la configuración:

Ventana de terminal
PROBARA_RUN_NAME="Nightly regression" PROBARA_ENVIRONMENT=staging PROBARA_RUN_TAGS=nightly,e2e npx cypress run

Un nombre de más de 200 caracteres se recorta, y también una etiqueta de más de 80; las etiquetas que pasan de 50 se descartan, con una advertencia. Un entorno, un hito o un plan que supera su límite desactiva el envío, nombrando el campo: tiene que coincidir con un nombre de Probara, y uno recortado no coincidiría con ninguno.

Sin el plugin, cada spec reporta en una ejecución propia, porque Cypress nunca avisa al reporter de cuándo terminó toda la ejecución (registro).

El entorno, el hito y las configuraciones aceptan también ULIDs: run.environmentId, run.milestoneId y run.configurationUlids (PROBARA_ENVIRONMENT_ID, PROBARA_MILESTONE_ID, PROBARA_CONFIGURATION_ULIDS). Define una sola forma de cada uno, nunca las dos: las dos a la vez es un problema de configuración que desactiva el envío. Los nombres son la forma que hay que usar con un token de aplicación, que no puede buscar ULIDs.

  • Un nombre de entorno desconocido crea el entorno.
  • Un hito, un plan o una configuración desconocidos hacen que Probara rechace el informe (422, nombrando el campo): no se registra nada, y el registro dice por qué. Comprueba los nombres en Probara.

Una ejecución registra de dónde viene: la rama, el commit y la URL del build de CI, leídos de las variables de GitHub Actions, GitLab CI, CircleCI, Azure Pipelines, Jenkins, Bitbucket Pipelines y Buildkite (qué rellena cada CI). Sustituye un campo con source o su variable, o no envíes ninguno:

OpciónVariableValor por defecto
source.branchPROBARA_BRANCHdetectado del CI
source.commitPROBARA_COMMITdetectado del CI
source.buildUrlPROBARA_BUILD_URLdetectado del CI
source: false—no envía origen

run.ulid (PROBARA_RUN_ULID) reporta en una ejecución que ya existe, como una que probara run create creó para las máquinas de un pipeline (sharding) o una que una persona creó en Probara (selección de pruebas). El reporter añade sus resultados a esa ejecución y la deja abierta:

$ PROBARA_RUN_ULID=01J9Z3K4M5N6P7Q8R9S0T1V2W3 npx cypress run
[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked)
[probara] Recorded 3 results (2 new cases, 0 unmatched) in R-1 (open): https://app.probara.net/projects/SHOP/runs/R-1
[probara] The run R-1 of SHOP stays open: close it in Probara, or with probara run close --project SHOP --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3

Las opciones de una ejecución nueva se ignoran entonces, con una advertencia: la ejecución conserva su propio nombre, entorno, hito y configuraciones.

[probara] Ignored name: a reused run (run.ulid) keeps its own

Para obtener el ULID de una ejecución en Probara, abre la ejecución y elige Copiar ULID de la ejecución en Acciones de la ejecución (el menú de la cabecera de la ejecución).

La ejecuciónAl final de cypress run
Creada por el reporterSe cierra, sea cual sea el código de salida de las pruebas
Reutilizada (run.ulid, run.ulids)Queda abierta: la cierra quien la creó
Cualquiera, si un informe falló tras sus reintentosQueda abierta: el registro la nombra, y el error dice qué hacer

closeRun (PROBARA_CLOSE_RUN) decide para cada ejecución: true cierra también una reutilizada, false deja abierta una creada. closeRuns decide por proyecto ({ SHOP: true, WEB: false }) cuando closeRun no está definido. Cierra una ejecución a mano con la CLI de Probara:

Ventana de terminal
npx @probara/cli run close --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3

Cada intento se envía con el veredicto del propio Cypress:

Lo que reporta CypressEstado
Una prueba que pasópassed
Una prueba que falló: una aserción, un error, un tiempo agotadofailed
Un intento que Cypress va a volver a ejecutar (un reintento)failed
it.skip, o this.skip() en la prueba o en un beforeEachskipped
Una prueba que un beforeEach fallido impidió ejecutarskipped
Un beforeEach o before que falla, reportado como "before each" hook for "…"failed, con ese nombre
Una spec que lanza un error al cargarse (An uncaught error was detected outside of a test)failed
Una spec que Cypress no puede analizarfailed, como Spec failed to run

El reporter nunca envía blocked por su cuenta: mapea un estado a él cuando lo necesites (mapeo de estados). Un resultado lleva el estado, la duración y la hora de inicio que reportó Cypress, y el error de un intento fallido en sus notas, con su mensaje y su traza y sin los colores de la terminal.

Un beforeEach o un before no pertenece a ninguna prueba propia: lo que hizo pertenece a la prueba para la que se ejecuta. Cuando falla, Cypress reporta el fallo con una prueba a la que da el nombre del hook y de la prueba en curso, y el reporter conserva ese nombre, que es también el que da la importación JUnit.

Un hook que falla una vez y pasa en el reintento es una prueba con dos resultados: el intento fallido y el que pasó. Un hook que falla en todos los intentos, con retries.runMode: 1:

cypress/e2e/hooks.cy.js
describe('Checkout', () => {
beforeEach(() => {
throw new Error('the cart service is down');
});
it('never runs', () => {});
it('never runs either', () => {});
});
describe('Profile', () => {
it('still runs', () => {});
});
cypress/e2e/hooks.cy.js > Checkout never runs failed
cypress/e2e/hooks.cy.js > Checkout "before each" hook for "never runs" failed
cypress/e2e/hooks.cy.js > Checkout never runs either skipped
cypress/e2e/hooks.cy.js > Profile still runs passed
  • Checkout never runs es el primer intento de la prueba, que falló porque falló su hook y que Cypress volvió a ejecutar.
  • "before each" hook for "never runs" es el fallo que Cypress no pudo superar.
  • Checkout never runs either no llegó a ejecutarse: el reporter envía como omitida cada prueba de la suite que no reportó ningún intento, algo que un informe JUnit no puede hacer, porque una prueba así no deja rastro en él. No se sabe que esté rota, solo que no se ejecutó.
  • Profile still runs: un beforeEach que falla detiene el resto de su propio describe, nunca el resto de la spec.

Una spec cuyo código de nivel superior lanza un error mientras Cypress la carga es un resultado fallido, con el nombre que le da Cypress, y se reintenta como cualquier prueba:

cypress/e2e/throws.cy.js > An uncaught error was detected outside of a test

Una spec que Cypress no puede analizar (un error de sintaxis) no ejecuta ninguna prueba. El plugin convierte el fallo que contó Cypress en un resultado fallido, para que una spec rota nunca aparezca en verde:

cypress/e2e/broken.cy.js > Spec failed to run

Sus notas dicen Cypress could not run this spec: 1 failure(s), no test ran, y su caso queda solo en la suite de la spec. Sin el plugin, ese resultado no existe.

Cypress termina un cypress run con el número de sus propias pruebas fallidas, y reportar no cambia nada de eso: una prueba que falla dos veces es una prueba fallida, y el fallo de un hook es una prueba propia. Lo que registró Probara (cada intento, un estado mapeado, un resultado filtrado, una ejecución que no se pudo enviar) nunca llega al código de salida.

statusMapping envía un estado como otro; statusFilter no envía ningún resultado con los estados indicados, después del mapeo. Ambos aceptan passed, failed, skipped y blocked.

reporterOptions: { projectId: 'SHOP', statusMapping: { failed: 'blocked' } },
$ npx cypress run --spec cypress/e2e/cart.cy.js
[probara] Sending 5 results of 5 tests (3 passed, 0 failed, 1 skipped, 1 blocked)

Con statusFilter: ['failed'] en su lugar, el intento fallido no se envía, y la línea Sending dice cuántos se dejaron fuera:

[probara] Sending 4 results of 4 tests (3 passed, 0 failed, 1 skipped, 0 blocked); 1 left out by statusFilter

Como variables: PROBARA_STATUS_MAPPING=failed=blocked,skipped=passed y PROBARA_STATUS_FILTER=skipped,blocked. Un valor que no es un estado, o un estado mapeado dos veces, es un problema de configuración que desactiva el envío. Cypress sigue haciendo fallar el comando: el mapeo y el filtro solo cambian lo que registra Probara.

  • Filtrar skipped deja fuera mucho: cada it.skip y cada prueba que un hook fallido impidió ejecutar.
  • blocked distingue los fallos que no son de la propia prueba: mapea failed a blocked cuando el fallo de un hook no deba leerse como una prueba que falla.

Cada intento es un resultado propio, en el orden en que se ejecutaron los intentos, cada uno con su estado, su duración, su error, sus pasos y sus archivos. Cuántos intentos hace Cypress lo decide su propio ajuste, retries:

cypress.config.js
module.exports = defineConfig({
e2e: {
reporter: '@probara/cypress-reporter',
reporterOptions: { projectId: 'SHOP' },
setupNodeEvents(on, config) {
return probaraNodeEvents(on, config);
},
retries: { runMode: 1 },
},
});
$ npx cypress run --spec cypress/e2e/retry.cy.js
[probara] Sending 2 results of 1 test (1 passed, 1 failed, 0 skipped, 0 blocked)
  • Qué muestra Probara. El caso de la ejecución conserva el último resultado (passed aquí), y cada intento queda en su historial: una prueba inestable es un caso cuyo historial mezcla fallos y aciertos en la misma ejecución. La línea Sending lo muestra: más resultados que pruebas.
  • El número de intento. Desde el segundo intento, el resultado lleva un parámetro attempt (2, 3, …), junto a browser. Ninguno forma parte de la clave de automatización.
  • Sin marca de inestable. Los propios intentos son la evidencia. probara import junit solo conserva el último intento de una prueba reintentada, así que una batería que pasa de la importación JUnit al reporter gana los intentos anteriores en el historial de cada caso inestable.
  • Cada intento empieza vacío. Lo que dijeron los helpers probara.* pertenece al intento que lo dijo: los pasos, los archivos y los metadatos de un reintento son suyos, nunca heredados.
  • Capturas de un reintento. Cada intento fallido recibe la captura que Cypress tomó para él.
  • El resumen propio de Cypress cuenta cada prueba una vez, por su último intento; Probara cuenta cada intento.

Para enviar solo el último intento, no reintentes en Cypress: ninguna opción del reporter descarta intentos.

Cuando un informe no se puede enviar (Probara inalcanzable, un token rechazado, un informe que falló tras sus reintentos), sus resultados se pierden salvo que los guardes. Define un archivo de resultados, y el reporter escribe en él lo que no pudo enviar; probara import results lo envía más tarde, a las mismas ejecuciones.

reporterOptions: { projectId: 'SHOP', resultsFile: 'results/probara-results.json' },

O PROBARA_RESULTS_FILE=results/probara-results.json, relativo al directorio desde el que se lanzó cypress run.

$ npx cypress run
[probara] Sending 1 result of 1 test (1 passed, 0 failed, 0 skipped, 0 blocked)
[probara] 1 result was not sent: Probara answered 403 forbidden: <message from Probara>. No run was created or updated
[probara] Wrote the 1 result that was not sent to /work/shop/results/probara-results.json: send them with probara import results /work/shop/results/probara-results.json

Después, desde cualquier job que tenga el token, envía lo que quedó pendiente:

Ventana de terminal
npx @probara/cli import results 'results/probara-results*.json'

Pon el glob entre comillas: probara lo expande, y coincide con el archivo y sus hermanos.

  • Solo cuando hace falta. El archivo solo se escribe cuando algo no se envió: cuando todos los resultados llegaron, no hay archivo.
  • A las mismas ejecuciones. El archivo nombra las ejecuciones a las que pertenecen sus resultados, los ajustes que los enviaron (proyecto, ejecución, rootDir, createMissingCases) y cada resultado tal como lo construyó el reporter, así que llega a los mismos casos desde cualquier máquina. Nunca el token.
  • Nunca encima de un archivo anterior. Cuando ya hay un archivo en esa ruta (el de otra máquina, o el de una ejecución anterior), el reporter escribe en el primer hermano libre: probara-results-2.json, después -3, y así sucesivamente.
  • Estados antes del mapeo. El archivo guarda cada estado antes de statusMapping, que se vuelve a aplicar al enviar el archivo.
ArchivosEn el archivo de resultados
Cuerpos y archivos de probara.attach(), la salida de consolaCopiados junto a él, en probara-results-attachments/, y nombrados relativos al archivo
Capturas y vídeosNombrados por su ruta absoluta, sin copiar

Mueve o descarga el archivo y su carpeta de adjuntos juntos, e impórtalo desde ahí: un artefacto de CI que descarga otro job conserva esos adjuntos. Una máquina que nunca tuvo las capturas y los vídeos no puede enviarlos.

Con el envío desactivado (PROBARA_ENABLED=false, o sin token), el reporter escribe todos los resultados en el archivo. Ejecuta las pruebas donde no hay token, y envía el archivo desde un job que lo tenga:

Ventana de terminal
PROBARA_ENABLED=false PROBARA_PROJECT=SHOP PROBARA_RESULTS_FILE=results/probara-results.json npx cypress run
npx @probara/cli import results 'results/probara-results*.json'

El mismo archivo muestra qué se enviaría sin enviarlo (comprobar qué se enviaría). La importación (varios archivos y globs, --dry-run, códigos de salida) está en probara import results (en inglés).

assignFailedTo nombra a las personas que revisan los fallos. Cada informe pide a Probara que asigne cada caso de la ejecución que deja fallido, y que aún no tiene responsable, a una de ellas, por turnos, para que una ejecución nocturna fallida llegue a la lista de alguien sin que nadie tenga que clasificarla antes.

reporterOptions: {
projectId: 'SHOP',
assignFailedTo: ['ana@example.com', 'bo@example.com'],
},

O desde el entorno: PROBARA_ASSIGN_FAILED_TO=ana@example.com,bo@example.com.

ReglaPor qué
Solo los casos de la ejecución que un informe deja en failedLos resultados que pasaron, omitidos o bloqueados no necesitan a nadie
Solo los casos de la ejecución sin responsableNunca se sustituye a un responsable: alguien ya se ocupa
Solo miembros activos que pueden ejecutar pruebas en el proyectoUn caso no se puede asignar a quien no puede trabajar en él
Los miembros indicados se turnan, en el orden en que los indicasLos fallos se reparten, no se acumulan en el primer nombre
Un email que no coincide con ningún miembro así se omiteLos resultados se registran igualmente; la advertencia de Probara los cuenta
  • Decide el último intento. Una prueba inestable que pasa en su reintento deja su caso en passed, así que nunca se asigna, por muchos intentos suyos que fallaran.
  • Después de statusMapping. Con statusMapping: { failed: 'blocked' }, nada queda fallido, así que nada se asigna.
  • La advertencia nunca nombra los emails, solo cuántos se omitieron: [probara] Probara warned: <message from Probara>.
  • La lista se recorta y se deduplica. Más de 20 emails, o un valor que no es un email, desactiva el envío, nombrando assignFailedTo.

Relacionado: Configuración · Sharding y proyectos · Solución de problemas · Fuente: runs.md, statuses.md, specs.md, retries.md, results-file.md, assign-failed.md