Resultados, estados y reintentos en Jest
Cada comando jest reporta en una ejecución de Probara: una ejecución automatizada nueva por
defecto, que se cierra al final, o una existente. Cada intento de cada prueba es un resultado en
ella, con el veredicto del propio Jest. 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.
La ejecución
Sección titulada «La ejecución»Estas opciones describen la ejecución que crea el reporter:
reporters: [ 'default', [ '@probara/jest-reporter', { run: { name: 'Nightly regression', description: 'Every night on main, against staging.', environment: 'staging', milestone: 'Sprint 12', plan: 'PLAN-2', configurations: [ { group: 'Node', name: '22' }, { group: 'OS', name: 'Linux' }, ], tags: ['nightly', 'unit'], }, }, ],],| Opción | Variable | Qué define |
|---|---|---|
run.name | PROBARA_RUN_NAME | El nombre. Por defecto: el nombre del build de CI (CI #42), si no Automated run <date> <time> UTC |
run.description | PROBARA_RUN_DESCRIPTION | La descripción, hasta 2000 caracteres (si es más larga se recorta, con una advertencia) |
run.environment | PROBARA_ENVIRONMENT | El entorno, por nombre: se crea en el proyecto si ninguno tiene ese nombre |
run.milestone | PROBARA_MILESTONE | El hito, por ID visible (M-3) o nombre exacto |
run.plan | PROBARA_PLAN | El plan de pruebas, por ID visible (PLAN-2) o nombre exacto: la ejecución empieza con los casos del plan |
run.configurations | PROBARA_CONFIGURATIONS | Valores de configuración por grupo y nombre (Node=22,OS=Linux), cada grupo una vez |
run.tags | PROBARA_RUN_TAGS | Etiquetas (nightly,unit), hasta 50 |
La misma ejecución desde el entorno de un paso de CI, con el proyecto en la configuración:
PROBARA_RUN_NAME="Nightly regression" PROBARA_ENVIRONMENT=staging PROBARA_RUN_TAGS=nightly,unit npx jestNombres o ULIDs
Sección titulada «Nombres o ULIDs»El entorno, el hito y las configuraciones también aceptan 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 ambas: las dos a la vez son
un problema de configuración que desactiva el envío. Los nombres son la forma que debes usar con un
token de aplicación, que no puede consultar ULIDs.
- Un nombre de entorno desconocido crea el entorno.
- Un hito, un plan o una configuración desconocidos hacen que Probara rechace el primer informe
(
422, nombrando el campo): no se registra nada, y el registro dice por qué. Comprueba los nombres en Probara.
Origen de la ejecución
Sección titulada «Origen de la ejecución»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 (lo que rellena cada CI). Sustituye un
campo con source o su variable, o no envíes ninguno:
reporters: ['default', ['@probara/jest-reporter', { source: { branch: 'release/2.4' } }]],| Opción | Variable | Valor por defecto |
|---|---|---|
source.branch | PROBARA_BRANCH | detectado del CI |
source.commit | PROBARA_COMMIT | detectado del CI |
source.buildUrl | PROBARA_BUILD_URL | detectado del CI |
source: false | — | no envía origen |
El nombre del build de CI también da nombre a la ejecución cuando run.name no está definido.
Una ejecución existente
Sección titulada «Una ejecución existente»run.ulid (PROBARA_RUN_ULID) reporta en una ejecución que ya existe, como la que creó
probara run create para los shards de un pipeline
(sharding) o una que alguien 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 jest[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-1Las 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 ownPara 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ón | Al final de jest |
|---|---|
| Creada por el reporter | Se cierra, cuando se enviaron todos los resultados y archivos |
Reutilizada (run.ulid) | Queda abierta: la cierra quien la creó |
Creada en una sesión --watch | Queda abierta, para la siguiente repetición |
| Cualquiera, cuando un informe falló tras los reintentos | Queda abierta: el registro la nombra, y el error dice qué hacer |
closeRun (PROBARA_CLOSE_RUN) decide para cada ejecución de un comando que no sea una sesión
watch: true cierra también una ejecución reutilizada, false deja abierta una creada. closeRuns
decide por proyecto ({ SHOP: true, WEB: false }) cuando closeRun no está definido. Cuando falla un
informe, lo que no se envió puede ir a un archivo de resultados, que
probara import results envía después a la misma ejecución, y la cierra como lo habría hecho el
reporter.
Cierra una ejecución a mano con la CLI de Probara:
npx @probara/cli run close --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3Con varios proyectos de Probara, cada proyecto tiene su propia ejecución. El nombre, la descripción, el entorno (por nombre) y las etiquetas van con cada ejecución nueva; el hito, el plan y las configuraciones solo van con la ejecución del proyecto configurado.
Estados
Sección titulada «Estados»Cada intento se envía con el veredicto del propio Jest:
| El intento | Estado |
|---|---|
| Aprobado | passed |
Fallido: una aserción, un error, un tiempo agotado, un beforeAll o beforeEach que lanzó un error | failed |
test.skip, xit, un describe omitido, una prueba excluida por .only o -t | skipped |
test.todo | skipped, con la nota Todo |
test.failing, y lanzó un error como se esperaba | passed |
test.failing, pero pasó | failed |
El reporter nunca envía blocked por su cuenta: mapea un estado a él
(más abajo) cuando lo necesites.
test('passes', () => {});
test('fails', () => { expect(1 + 1).toBe(3);});
test.skip('is skipped', () => {});
test.todo('is not written yet');
test.failing('is a known bug', () => { expect(0.1 + 0.2).toBe(0.3);});[ { "automationKey": "tests/statuses.test.js > passes", "status": "passed" }, { "automationKey": "tests/statuses.test.js > fails", "status": "failed" }, { "automationKey": "tests/statuses.test.js > is not written yet", "status": "skipped", "notes": "Todo" }, { "automationKey": "tests/statuses.test.js > is a known bug", "status": "passed" }, { "automationKey": "tests/statuses.test.js > is skipped", "status": "skipped" }]- Orden. Las pruebas se envían en el orden en que las reporta Jest: las que se ejecutaron y las todo a medida que terminan, y después las pruebas omitidas del archivo, cuando este termina.
- Los errores van a las notas del resultado: cada error del intento, con su mensaje y su traza, sin los colores de la terminal, después de un comentario si la prueba escribió uno.
- Las pruebas todo nunca se pierden: son resultados omitidos con la nota
Todo, así que el caso muestra lo que queda por escribir.probara import junitlas registra como aprobadas, porque jest-junit las escribe como testcases aprobados. - Los fallos esperados son los de Jest: una prueba
test.failingque lanza un error hace lo que debe, así que pasa, y la ejecución sigue en verde en Probara igual que en Jest. Cuando se corrige el bug, la prueba pasa, Jest la hace fallar, y Probara también, lo que te recuerda quitar.failing. - Las pruebas omitidas no tienen duración: Jest no las ejecuta. En Jest 29 reciben la hora de inicio de su archivo; Jest 30 da a cada una la suya.
Un hook que falla después de las pruebas
Sección titulada «Un hook que falla después de las pruebas»Un hook afterAll que lanza un error hace fallar el archivo de prueba después de que sus pruebas
pasaron. Jest muestra el error y hace fallar el comando; sus pruebas siguen en verde. Para que
Probara tampoco muestre el archivo en verde, el reporter envía un resultado fallido más para el
archivo, el que escribe jest-junit, con el error en sus notas:
afterAll(() => { throw new Error('Could not drop the test database');});
test('creates an order', () => {});[ { "automationKey": "tests/cleanup.test.js > creates an order", "status": "passed" }, { "automationKey": "tests/cleanup.test.js > Test execution failure: could be caused by test hooks like 'afterAll'.", "status": "failed" }]Su clave es la que probara import junit da al mismo fallo en el informe de jest-junit, así que ambas
herramientas lo registran en el mismo caso.
Un archivo que Jest no puede ejecutar
Sección titulada «Un archivo que Jest no puede ejecutar»Un archivo de prueba que falla antes de que existan sus pruebas (un error de sintaxis, una importación que lanza un error) no tiene pruebas que reportar. El reporter lo nombra en una advertencia, y reporta los demás archivos como siempre:
$ npx jest[probara] Could not report tests/broken.test.js: Jest could not run it (Cannot find module './missing-module' from 'tests/broken.test.js')[probara] Sending 1 result of 1 test (1 passed, 0 failed, 0 skipped, 0 blocked)[probara] Recorded 1 result (1 new case, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1Corrige el archivo: la salida del propio Jest muestra el error completo.
Mapeo y filtro de estados
Sección titulada «Mapeo y filtro de estados»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:
reporters: [ 'default', [ '@probara/jest-reporter', { statusMapping: { failed: 'blocked' }, statusFilter: ['skipped'] }, ],],Con una prueba que pasa, una que falla y un test.todo:
$ npx jest[probara] Sending 2 results of 2 tests (1 passed, 0 failed, 0 skipped, 1 blocked); 1 left out by statusFilter[probara] Recorded 2 results (2 new cases, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1[probara] Filtered out 1 result by their status (statusFilter): not sentComo 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. statusFilter: ['skipped'] también omite
las pruebas todo: son resultados omitidos. El mapeo solo cambia lo que registra Probara: el código de
salida de Jest sigue siendo el de las pruebas.
Reintentos y pruebas inestables
Sección titulada «Reintentos y pruebas inestables»Cada intento de una prueba es un resultado propio. Una prueba que jest.retryTimes(2) reintenta dos
veces envía tres resultados, en el orden en que se ejecutaron, cada uno con su estado, su duración,
su error, sus pasos y sus archivos.
jest.retryTimes(1);
let attempts = 0;
test('loads the dashboard', () => { attempts += 1; // Fails the first time, passes on the retry. expect(attempts).toBe(2);});$ npx jest[probara] Sending 2 results of 1 test (1 passed, 1 failed, 0 skipped, 0 blocked)[probara] Recorded 2 results (1 new case, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1- Lo que muestra Probara. El caso de la ejecución conserva el último resultado (
passedaquí), y cada intento queda en su historial: una prueba inestable es un caso cuyo historial mezcla fallos y aprobados en la misma ejecución. El registro también lo dice: más resultados que pruebas. - Sin marca de inestable. El reporter no marca los intentos como inestables: los propios intentos
son la evidencia. jest-junit y
probara import junitconservan solo el último intento de una prueba reintentada. - Cada intento empieza vacío. Las llamadas
probara.*se aplican al intento que las hizo, así que un reintento que termina antes no hereda los pasos, los archivos ni los metadatos del primer intento. - El resumen de Jest cuenta la prueba una vez, por su último intento; Probara cuenta cada intento.
Por defecto, Jest reintenta las pruebas fallidas de un archivo después de las demás pruebas del
archivo; jest.retryTimes(n, { retryImmediately: true }) de Jest 30 reintenta cada una al momento.
En ambos casos, cada intento se envía cuando termina, así que el orden de los intentos de una prueba
es siempre el orden en que se ejecutaron.
| Jest | Qué cambia para Probara |
|---|---|
retryImmediately, waitBeforeRetry (Jest 30) | Cuándo se ejecuta cada intento; cada intento sigue siendo un resultado |
logErrorsBeforeRetry | Lo que muestra Jest; el error de cada intento fallido está igualmente en su propio resultado |
test.concurrent en Jest 29 | Jest nunca lo reintenta: un resultado |
test.concurrent en Jest 30.0 a 30.4 | Cada intento es un resultado, pero las llamadas probara.* de un reintento van al primer intento: Jest no dice cuál se ejecuta |
test.concurrent en Jest 30.5 y posteriores | Cada intento es un resultado, con sus propias llamadas probara.* |
Para enviar solo el último intento, no reintentes en Jest: ninguna opción del reporter descarta intentos. Para que los fallos de las pruebas reintentadas no cuenten, mapéalos, sabiendo que se aplica a todos los fallos.
Archivo de resultados
Sección titulada «Archivo de resultados»Cuando un informe no se puede enviar (Probara inalcanzable, la red caída, un informe rechazado), sus
resultados se pierden salvo que los guardes. Define un archivo de resultados, y el reporter escribe
en él lo que no pudo enviar al final de la ejecución; probara import results lo envía después, a
las mismas ejecuciones.
reporters: ['default', ['@probara/jest-reporter', { resultsFile: 'probara-results.json' }]],O PROBARA_RESULTS_FILE=probara-results.json, relativo al directorio en el que se ejecuta jest.
$ PROBARA_RESULTS_FILE=probara-results.json npx jest[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked)[probara] 3 results were not sent: Probara answered 403 forbidden: <message from Probara>. No run was created or updated[probara] Wrote the 3 results that were not sent to /work/shop/probara-results.json: send them with probara import results /work/shop/probara-results.jsonDespués, desde cualquier job que tenga el token, envía lo que haya quedado:
npx @probara/cli import results 'probara-results*.json'Pon el glob entre comillas: probara lo expande, y coincide con el archivo y sus hermanos. Cuando no
coincide nada, no quedó nada sin enviar: la importación lo dice y termina con 0.
- Solo cuando hace falta. El archivo solo se escribe cuando algo no se envió: si todos los resultados llegaron, no hay archivo.
- A las mismas ejecuciones. El archivo nombra las ejecuciones a las que pertenecen sus resultados: una ejecución que el informe fallido dejó abierta recibe el resto de sus resultados, y una ejecución que nunca se creó la crea la importación con el mismo nombre y los mismos ajustes. Las ejecuciones se cierran como las habría cerrado el reporter.
- La importación lo consume.
probara import resultsenvía cada archivo por separado, y después lo elimina (con su carpeta de adjuntos) cuando se enviaron todos sus resultados, o lo reescribe con solo lo que sigue sin enviarse. Importar de nuevo nunca envía un resultado dos veces, así que la importación se puede ejecutar sin riesgo en cada pipeline.--dry-runnunca toca los archivos. - Nunca toca un archivo anterior. Cuando ya hay un archivo en esa ruta (el de otro shard en un
disco compartido, o el de una ejecución anterior), el reporter lo deja como está y escribe en el
primer hermano libre:
probara-results-2.json, después-3, y así sucesivamente, cada uno con su propia carpeta de adjuntos. El registro nombra el archivo escrito, y el glob los importa todos, del más antiguo al más reciente. - Nunca a medio escribir. Cada archivo se escribe completo primero en un archivo temporal de la misma carpeta (con un nombre que empieza por punto, que el glob nunca encuentra), y después aparece de golpe con su nombre: una importación que se ejecuta a la vez ve el archivo completo o no lo ve.
Los adjuntos viajan con el archivo
Sección titulada «Los adjuntos viajan con el archivo»Los archivos que lleva un resultado (lo que copió probara.attach(), la salida de consola de
captureOutput) se guardan junto al archivo de resultados, en su carpeta de adjuntos
(probara-results-attachments/ para probara-results.json), y el archivo los nombra con rutas
relativas a sí mismo. Mueve o descarga el archivo y su carpeta juntos, a cualquier lugar, e impórtalo
desde allí: un artefacto de CI que descarga otro job conserva sus adjuntos.
Una subida que falla durante la importación no se guarda para otro intento: su resultado se registró, así que ya no está en el archivo, y la carpeta se va con el archivo cuando se enviaron todos los resultados. La importación lo registra y termina con 1.
Envío desactivado: guardarlo todo
Sección titulada «Envío desactivado: guardarlo todo»Con el envío desactivado (PROBARA_ENABLED=false, o sin token), el reporter escribe cada intento
en el archivo, incluidos los vínculos con los casos. Ejecuta las pruebas donde no hay token (un fork,
una máquina sin red), e importa el archivo desde un job que lo tenga:
$ PROBARA_ENABLED=false PROBARA_RESULTS_FILE=probara-results.json npx jest[probara] Wrote 3 results to /work/shop/probara-results.json: send them with probara import results /work/shop/probara-results.jsonEl mismo archivo muestra qué se enviaría sin enviarlo (comprobar qué se enviaría).
Guarda los archivos y sus carpetas de adjuntos como artefactos del job de pruebas, e impórtalos en un job (o paso) posterior que tenga el token:
- name: Run Jest tests run: npx jest env: PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }} PROBARA_RESULTS_FILE: probara-results.json- name: Send what Probara did not get if: always() run: npx --yes @probara/cli@0.2 import results 'probara-results*.json' env: PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }} PROBARA_ENABLED: ${{ secrets.PROBARA_API_TOKEN != '' }}Si Probara solo estuvo caído un momento, la importación envía el resto. Si sigue sin poder, la importación termina con 1 y conserva en cada archivo lo que no pudo enviar; los archivos que envió desaparecen.
Un archivo de resultados es una entrada de confianza: sus adjuntos se suben desde las rutas que nombra, así que importa solo los archivos que escribieron tus propios jobs. La importación omite, con una advertencia, un adjunto cuya ruta relativa sale de la carpeta del archivo; las rutas absolutas se conservan.
El formato
Sección titulada «El formato»La versión 1 de un documento JSON: el proyecto, las ejecuciones y los ajustes del reporter (nunca el
token), y después cada resultado tal como lo construyó el reporter, antes de statusMapping (que se
aplica cuando se envía el archivo). El formato completo está en el
archivo de resultados de core,
y la importación (varios archivos y globs, el resumen JSON, los códigos de salida) en
probara import results.
Asignar resultados fallidos
Sección titulada «Asignar resultados fallidos»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 que falla llegue a la lista de alguien sin que nadie tenga que
clasificarla antes.
reporters: [ 'default', [ '@probara/jest-reporter', { assignFailedTo: ['ana@example.com', 'bo@example.com', 'cy@example.com'] }, ],],O desde el entorno: PROBARA_ASSIGN_FAILED_TO=ana@example.com,bo@example.com. Con ana@example.com
y bo@example.com como miembros del proyecto y cy@example.com no, dos casos fallidos van a Ana y a
Bo, y Probara indica que un correo no coincidió con nadie:
$ npx jest[probara] Sending 3 results of 3 tests (1 passed, 2 failed, 0 skipped, 0 blocked)[probara] Probara warned: assignFailedTo: 1 of 3 emails did not match a member who can be assigned in this project[probara] Recorded 3 results (3 new cases, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1| Regla | Por qué |
|---|---|
Solo los casos de la ejecución que un informe deja en failed | Los resultados aprobados, omitidos y bloqueados no necesitan a nadie |
| Solo los casos de la ejecución sin responsable | Un responsable existente nunca se sustituye: alguien ya se encarga |
| Solo miembros activos que pueden ejecutar pruebas en el proyecto | Un caso no se puede asignar a quien no puede trabajar en él |
| Los miembros de la lista se turnan, en el orden en que los indicas | Los fallos se reparten, no se acumulan en el primer nombre |
| Un correo que no coincide con ningún miembro así se omite | Los resultados se registran igualmente; la advertencia de Probara los cuenta |
- Después de
statusMapping. El estado que cuenta es el que registra Probara: constatusMapping: { failed: 'blocked' }no hay nada fallido, así que no se asigna nada. - La advertencia nunca nombra los correos, solo cuántos se omitieron: el registro de un job de CI no es el lugar para listar quién es miembro y quién no. Compara la lista con los miembros del proyecto en Probara.
- Los turnos empiezan de nuevo con cada informe: cada informe (un bloque de hasta 500 resultados, un shard, una repetición en modo watch) da su primer caso fallido al primer miembro de la lista.
- Cada informe de la ejecución lo pide, con la misma lista: una ejecución con varios proyectos de Probara lo pide en la ejecución de cada proyecto, y los shards de una ejecución compartida asignan cada uno los casos que dejan fallidos.
- Un archivo de resultados conserva la lista.
probara import resultsla envía con los resultados, salvo que--assign-failed-tooPROBARA_ASSIGN_FAILED_TOnombren a otras personas.
Relacionado: Configuración · Sharding y proyectos · Solución de problemas · Fuente: runs.md, statuses.md, retries.md, results-file.md, assign-failed.md