Ir al contenido

Resultados y reintentos de Playwright

Cada playwright test envía sus resultados a una ejecución de Probara: una ejecución automatizada nueva por defecto, cerrada al final, o una existente. Esta página cubre esa ejecución, el estado de cada intento, los reintentos y lo que pasa con los resultados que no se pudieron enviar.

Estas opciones describen la ejecución que crea el reporter:

reporter: [
[
'@probara/playwright-reporter',
{
run: {
name: 'Nightly regression',
description: 'Every night on main, against staging.',
environment: 'staging',
milestone: 'Sprint 12',
plan: 'PLAN-2',
configurations: [
{ group: 'Browser', name: 'Chromium' },
{ 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_DESCRIPTIONLa descripción, de hasta 2000 caracteres (lo que exceda se recorta, con una advertencia)
run.environmentPROBARA_ENVIRONMENTEl entorno, por nombre: se crea en el proyecto si no hay ninguno con ese nombre
run.milestonePROBARA_MILESTONEEl hito, por ID visible (M-3) o por nombre exacto
run.planPROBARA_PLANEl plan de prueba, por ID visible (PLAN-2) o por nombre exacto: la ejecución empieza con los casos del plan
run.configurationsPROBARA_CONFIGURATIONSValores de configuración por grupo y nombre (Browser=Chromium,OS=Linux), cada grupo una vez
run.tagsPROBARA_RUN_TAGSEtiquetas (nightly,e2e), hasta 50

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). Usa una sola forma para cada uno, nunca las dos: las dos a la vez son un problema de configuración que desactiva el envío. Con un token de aplicación, usa los nombres: el token 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 explica por qué. Revisa 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 del CI. Gana el primer proveedor que coincide:

CISe detecta porNombre de la ejecuciónRama, commit y URL del build desde
GitHub ActionsGITHUB_ACTIONS=trueGITHUB_WORKFLOW #GITHUB_RUN_NUMBERGITHUB_HEAD_REF o GITHUB_REF_NAME, GITHUB_SHA, la URL de la ejecución
GitLab CIGITLAB_CI=trueCI_PROJECT_NAME #CI_PIPELINE_IIDCI_MERGE_REQUEST_SOURCE_BRANCH_NAME o CI_COMMIT_REF_NAME, CI_COMMIT_SHA, CI_PIPELINE_URL
CircleCICIRCLECI=trueCIRCLE_PROJECT_REPONAME #CIRCLE_BUILD_NUMCIRCLE_BRANCH, CIRCLE_SHA1, CIRCLE_BUILD_URL
Azure PipelinesTF_BUILD=TrueBUILD_DEFINITIONNAME #BUILD_BUILDNUMBERLa rama de origen, BUILD_SOURCEVERSION, la URL de los resultados del build
JenkinsJENKINS_URL definidaJOB_NAME #BUILD_NUMBERBRANCH_NAME o GIT_BRANCH, GIT_COMMIT, BUILD_URL
Bitbucket PipelinesBITBUCKET_BUILD_NUMBERBITBUCKET_REPO_SLUG #BITBUCKET_BUILD_NUMBERBITBUCKET_BRANCH, BITBUCKET_COMMIT, la URL del pipeline
BuildkiteBUILDKITE=trueBUILDKITE_PIPELINE_SLUG #BUILDKITE_BUILD_NUMBERBUILDKITE_BRANCH, BUILDKITE_COMMIT, BUILDKITE_BUILD_URL

Un build de una etiqueta no envía rama. Los valores no válidos se descartan, nunca se envían. Sustituye un campo con source o con su variable, o no envíes ninguno:

reporter: [['@probara/playwright-reporter', { source: { branch: 'release/2.4' } }]],
OpciónVariablePor 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) envía a una ejecución que ya existe, como la que probara run create crea para los shards de un pipeline (shards). Las opciones de una ejecución nueva se ignoran entonces, con una advertencia: la ejecución conserva su propio nombre, entorno, hito y configuraciones.

Una ejecución que crea el reporter se cierra al final, cuando se han enviado todos los resultados y archivos; una reutilizada queda abierta. closeRun (PROBARA_CLOSE_RUN) decide para cualquier ejecución. Cuando un informe falla, la ejecución queda abierta: el registro la nombra, y lo que no se envió puede ir a un archivo de resultados.

assignFailedTo (PROBARA_ASSIGN_FAILED_TO=ana@example.com,bo@example.com) nombra hasta 20 miembros de la organización por email. Cada informe de la ejecución pide a Probara que asigne cada caso de la ejecución que deja fallido y sin responsable a uno de ellos, por turnos; un caso que ya tiene responsable lo conserva.

  • Los emails se recortan y cuentan una sola vez, sin distinguir mayúsculas. Un valor que no es un email, o más de 20 emails, es un problema de configuración que desactiva el envío.
  • Un email que no coincide con ningún miembro asignable en el proyecto no es un error: Probara los cuenta en una advertencia, que el reporter registra sin nombrarlos.

Cada intento se envía con el veredicto de Playwright: lo que hizo el intento comparado con lo que la prueba esperaba.

El intentoEstado
Pasópassed
Falló: una aserción, un error, un hook o un fixture lanzó un errorfailed
Agotó su tiempofailed
Se interrumpió (la ejecución se detuvo: Ctrl+C, --max-failures, un tiempo global)failed
test.skip(), test.fixme(), un describe omitidoskipped
test.fail(), y falló como se esperabapassed
test.fail(), pero pasófailed

El reporter nunca envía blocked por su cuenta: mapea un estado a él (abajo) cuando lo necesites.

tests/statuses.spec.ts
import { expect, test } from '@playwright/test';
test('passes', async () => {});
test('fails', async () => {
expect(1 + 1).toBe(3);
});
test('is skipped on CI', async () => {
test.skip(true, 'Needs the payment sandbox');
});
test.fixme('is not written yet', async () => {});
test('is a known bug', async () => {
test.fail(true, 'SHOP-99: totals round down');
expect(0.1 + 0.2).toBe(0.3);
});
[
{ "automationKey": "statuses.spec.ts > passes", "status": "passed" },
{ "automationKey": "statuses.spec.ts > fails", "status": "failed" },
{
"automationKey": "statuses.spec.ts > is skipped on CI",
"status": "skipped",
"notes": "Skipped: Needs the payment sandbox"
},
{ "automationKey": "statuses.spec.ts > is not written yet", "status": "skipped" },
{ "automationKey": "statuses.spec.ts > is a known bug", "status": "passed" }
]
  • Los errores van en las notas del resultado: todos los errores del intento, con su mensaje y su stack, después de un comentario si la prueba escribió uno.
  • Los motivos de omisión van en las notas como Skipped: <reason>, la misma línea que escribe probara import junit, a partir de test.skip(condition, reason) o test.fixme(condition, reason).
  • Los fallos esperados son los de Playwright: una prueba con test.fail() que falla hace lo que debe, así que pasa, y la ejecución sigue en verde en Probara igual que en Playwright. Cuando se corrige el bug, la prueba pasa, Playwright la hace fallar, y Probara también, para recordarte que quites test.fail().
  • Los tiempos agotados conservan el mensaje de Playwright (Test timeout of 30000ms exceeded.) en las notas.

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

reporter: [
[
'@probara/playwright-reporter',
{ statusMapping: { failed: 'blocked' }, statusFilter: ['skipped'] },
],
],

Con una prueba que pasa, una que falla y una omitida:

$ npx playwright test
[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 sent
[probara] Attached 1 file to results (0 skipped, 0 failed)

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. El mapeo solo cambia lo que registra Probara: el código de salida de Playwright sigue siendo el de las pruebas.

Cada intento de una prueba es un resultado propio. Una prueba reintentada dos veces envía tres resultados, en el orden en que se ejecutaron, cada uno con su estado, su duración, sus errores, sus pasos y sus archivos.

// playwright.config.ts (excerpt)
retries: 1,
tests/flaky.spec.ts
import { expect, test } from '@playwright/test';
test('loads the dashboard', async ({}, testInfo) => {
// Fails the first time, passes on the retry.
expect(testInfo.retry).toBe(1);
});
[
{ "automationKey": "flaky.spec.ts > loads the dashboard", "status": "failed" },
{ "automationKey": "flaky.spec.ts > loads the dashboard", "status": "passed" }
]
$ npx playwright test
[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
[probara] Attached 1 file to results (0 skipped, 0 failed)

El archivo es el contexto de error que Playwright escribió para el intento fallido.

  • 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. El registro también lo indica: más resultados que pruebas.
  • Sin marca de inestable. El reporter no marca los intentos como inestables: los propios intentos son la evidencia, y el veredicto de Playwright (flaky, cuando un reintento pasó) se queda en los informes de Playwright.
  • Cada intento empieza vacío. Los metadatos probara.* se aplican al intento que los definió, así que un reintento que se detiene antes no hereda los metadatos del primer intento.
  • Orden. Los resultados se envían en el orden en que Playwright termina los intentos; como el caso de la ejecución conserva el último resultado, el reintento final es el que muestra.

Para enviar solo el último intento, filtra en Playwright: ninguna opción del reporter descarta intentos. Para que los fallos de las pruebas reintentadas no cuenten en tus cifras, mapéalos, sabiendo que el mapeo se aplica a todos los fallos.

Cuando un informe no se puede enviar (Probara inaccesible, la red caída, un informe rechazado), sus resultados se pierden salvo que los conserves. 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 más tarde, a las mismas ejecuciones.

reporter: [['@probara/playwright-reporter', { resultsFile: 'probara-results.json' }]],

O PROBARA_RESULTS_FILE=probara-results.json, relativo al directorio en el que se ejecuta Playwright.

Guardar lo que no se pudo enviar y enviarlo después

Sección titulada «Guardar lo que no se pudo enviar y enviarlo después»
$ PROBARA_RESULTS_FILE=probara-results.json npx playwright test
[probara] Sending 2 results of 2 tests (2 passed, 0 failed, 0 skipped, 0 blocked)
[probara] 2 results were not sent: Probara answered 403 forbidden: <message from Probara>. No run was created or updated
[probara] Wrote the 2 results that were not sent to /work/shop/probara-results.json: send them with probara import results /work/shop/probara-results.json

Después, desde cualquier job que tenga el token, envía lo que quedó con la CLI de Probara:

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

Pon el glob entre comillas: probara lo expande, y coincide con el archivo y con los hermanos que se describen abajo. Si no coincide nada, no quedó nada sin enviar: la importación lo indica y termina con código 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 results envía cada archivo por separado y después lo borra (junto con su carpeta <name>-attachments/) cuando se enviaron todos sus resultados, o lo reescribe solo con lo que sigue pendiente. Importar otra vez nunca envía un resultado dos veces, así que es seguro ejecutar la importación en todos los pipelines. --dry-run nunca toca los archivos.
  • Nunca toca un archivo anterior. Si 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 entero primero en un archivo temporal de la misma carpeta (con un nombre que empieza por punto, que el glob nunca encuentra) y aparece con su nombre de golpe: una importación simultánea ve el archivo entero o nada, y una ejecución detenida a medias no deja ningún archivo parcial.
  • Adjuntos por ruta. Los archivos se referencian donde los escribió Playwright, por ruta absoluta: conserva la carpeta de salida (test-results/) en su sitio hasta que se envíe el archivo. Los cuerpos en memoria se escriben junto al archivo, en <name>-attachments/, y se referencian de forma relativa a él, así que el archivo y esa carpeta pueden moverse juntos. Una subida que falla durante la importación no se guarda para otro intento: su resultado ya se registró, así que ya no está en el archivo. La importación lo registra y termina con código 1.

Una segunda ejecución que no puede enviar mientras el archivo de la primera sigue ahí escribe un hermano:

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

Con el envío desactivado (PROBARA_ENABLED=false, o sin token), el reporter escribe todos los intentos en el archivo, con los vínculos a casos incluidos. Ejecuta las pruebas donde no hay token (un fork, una máquina sin red) e importa el archivo desde un job que sí lo tenga:

$ PROBARA_ENABLED=false PROBARA_RESULTS_FILE=probara-results.json npx playwright test
[probara] Wrote 2 results to /work/shop/probara-results.json: send them with probara import results /work/shop/probara-results.json

El mismo archivo muestra lo que se enviaría sin enviarlo: consulta comprobar qué se enviaría.

Guarda los archivos, sus carpetas <name>-attachments/ y la carpeta de salida como artefactos del job de pruebas, e impórtalos en un job posterior que tenga el token. Un archivo de resultados y su carpeta se pueden descargar en cualquier sitio; los archivos de la carpeta de salida se buscan en la ruta absoluta que tenían, así que restáurala en esa ruta, o importa en el mismo job:

- name: Run Playwright tests
run: npx playwright test
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 inaccesible un momento, la importación envía el resto. Si sigue sin poder, la importación termina con código 1 y conserva en cada archivo lo que no pudo enviar; los archivos que sí envió desaparecen.

Un archivo de resultados es una entrada de confianza: la importación sube los archivos que nombra, desde cualquier ruta que el job pueda leer, así que importa solo los archivos que escribieron tus propios jobs. Un adjunto cuya ruta relativa sale de la carpeta del archivo se deja fuera con una advertencia.

El archivo es 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 al enviar el archivo. El formato completo está en el archivo de resultados de @probara/core (en inglés), y la importación (varios archivos y globs, el resumen JSON, los códigos de salida) en probara import results.

Siguiente: una ejecución para pipelines con shards, o solución de problemas.