Ir al contenido

Migrar al reporter de Cypress

Vengas de donde vengas, el reporter son tres registros: el reporter de la configuración de Cypress, su plugin en setupNodeEvents y su archivo de soporte.

cypress.config.js
const { defineConfig } = require('cypress');
const { probaraNodeEvents } = require('@probara/cypress-reporter/setup');
module.exports = defineConfig({
e2e: {
reporter: '@probara/cypress-reporter',
reporterOptions: { projectId: 'SHOP' },
setupNodeEvents(on, config) {
return probaraNodeEvents(on, config);
},
},
});
cypress/support/e2e.js
import '@probara/cypress-reporter/support';

Si setupNodeEvents ya registra otros plugins (como el de la herramienta que dejas), consulta con otros plugins.

Vienes deVe a
El reporter junit de Cypress o cypress-junit, con probara import junitLa importación JUnit
El reporter de Qase para CypressQase
allure-cypressAllure Cypress
JUnit XML y trcli parse_junitTestRail

Si tu pipeline escribe JUnit XML con el reporter junit integrado en Cypress o con cypress-junit, y lo envía con probara import junit, el reporter puede sustituir ambos pasos sin desvincular ni un solo caso: da a cada prueba la clave de automatización que le da la importación.

// cypress.config.js, before
module.exports = defineConfig({
e2e: {
reporter: 'junit', // or 'cypress-junit'
reporterOptions: { mochaFile: 'reports/cypress-[hash].xml', includePending: true },
},
});
  1. Sustituye el reporter JUnit por este, y registra su plugin y su archivo de soporte (arriba). Cypress acepta un solo reporter: para conservar el XML durante un tiempo, declara ambos en cypress-multi-reporters.
  2. Comprueba las claves de ambos sobre las mismas specs: tienen que ser iguales.
  3. En CI, quita el paso de importación, y pasa PROBARA_API_TOKEN al paso de pruebas.
El informe JUnitAjuste del reporter
Escrito con las opciones por defecto, con la spec en el file de su suite raízNada: keyIncludesFile: true es el valor por defecto
Escrito sin ese atributo filekeyIncludesFile: false (PROBARA_KEY_INCLUDES_FILE)

Ambos caminos leen las mismas dos partes de una prueba: la ruta de la spec relativa a la raíz del proyecto, y un solo segmento de título, los títulos de sus describe y el de su it unidos por espacios, sin los IDs de caso. Ejecuta la importación desde la raíz del proyecto (o pasa --root-dir): la importación expresa la ruta de la spec respecto al directorio en el que se ejecuta, y el reporter respecto al projectRoot de Cypress.

Ejecuta la batería una vez con el reporter JUnit y otra con el archivo de resultados del reporter, con el envío desactivado, y compara las pruebas en seco de ambos: cada una imprime una línea por resultado, con su estado, su caso y su clave.

Ventana de terminal
npx cypress run # with the JUnit reporter
npx --yes @probara/cli@0.3 import junit 'reports/cypress-*.xml' --dry-run > junit.txt
PROBARA_ENABLED=false PROBARA_PROJECT=SHOP PROBARA_RESULTS_FILE=probara-results.json npx cypress run # with this reporter
npx --yes @probara/cli@0.3 import results 'probara-results*.json' --dry-run > reporter.txt
$ npx --yes @probara/cli@0.3 import results 'probara-results*.json' --dry-run
passed SHOP-12 cypress/e2e/cart.cy.js > Cart adds an item

Una línea cuya clave cambió es una prueba que recibiría un caso nuevo; las pruebas reintentadas y las que un hook fallido impidió ejecutar tienen más líneas del lado del reporter (qué cambia). Borra después el XML y el archivo de resultados.

La CLI lee el JUnit XML de Cypress como su dialecto cypress-junit desde la versión 0.3. Reconoce un informe por sus señas: una raíz <testsuites> llamada Mocha Tests, exactamente un testsuite con un file que es una spec de Cypress (cypress/ en su ruta, o un nombre .cy.*), y testcases cuyo classname es el final de su name. Un informe que renombró la raíz (testsuitesTitle), o specs fuera de cypress/ sin nombre .cy.*, se lee en cambio como generic: pasa --dialect cypress-junit a la importación.

Antes, dos pasos: Cypress escribe el XML, y la CLI lo envía.

- name: Run Cypress tests
run: npx cypress run
- name: Send the results
if: ${{ !cancelled() }}
run: npx --yes @probara/cli@0.3 import junit 'reports/cypress-*.xml'
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP

Después, un paso: el reporter, registrado en la configuración de Cypress, envía cada resultado cuando termina la ejecución.

- name: Run Cypress tests
run: npx cypress run
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP

Qué cambia respecto a la importación JUnit

Sección titulada «Qué cambia respecto a la importación JUnit»
Cypressprobara import junitEl reporter
Una prueba que falla y pasa en un reintentoUn resultado: el que pasóDos resultados de un caso: el intento fallido y después el que pasó
Una prueba que falla en todos los intentosUn resultado: el último falloUn resultado por intento
Un hook que falla en todos los intentosSolo el fallo del hookEl intento reintentado de la prueba, y el fallo del hook que nombra Cypress
Las pruebas que ese hook impidió ejecutarNada: no dejaron ningún testcaseUn resultado omitido cada una
Suite de un caso creadoSolo la specLa spec y los bloques describe de la prueba

El estado, el error en las notas, la duración y la hora de inicio son iguales. El reporter añade dos parámetros que el JUnit no tiene dónde poner: browser y, desde el segundo intento, attempt. La suite solo cambia dónde va un caso que crea el informe: un caso existente nunca se mueve.

Lo que ganas: cada intento de una prueba reintentada; la captura de cada intento fallido, y el vídeo con attachVideos; pasos anidados; archivos y salida de consola; enlaces e incidencias; los campos de los casos nuevos; la selección de pruebas; y los resultados fallidos asignados a las personas que indiques.

Pasar del reporter de Qase para Cypress es sobre todo cambiar nombres: ambos se registran como un reporter, un hook de setupNodeEvents y un archivo de soporte, y sus helpers se corresponden uno a uno. El único cambio que toca tus specs es la sintaxis del ID de caso.

// with Qase
it('(Qase ID: 12) adds an item', () => {
cy.get('.add').click();
});
// with Probara
it('SHOP-12 adds an item', () => {
cy.get('.add').click();
});

(Qase ID: 12) no es un ID de Probara y no vincula nada: se queda en el título y en la clave, y la prueba recibe un caso nuevo. No hay ninguna opción que lea la sintaxis de Qase. Cambia primero los IDs, o llama a probara.id('SHOP-12') sin tocar el título (vincular).

En una batería con QaseEn una batería con ProbaraQué cambia
(Qase ID: 12) en el título de un it o describeSHOP-12 en el título, o probara.id('SHOP-12')La sintaxis del ID
qase.title() / qase.suite()probara.title() / probara.suite()Lo mismo, para el caso que crea el informe
qase.fieldsprobara.fields({ ... })Solo tiene efecto cuando el informe crea un caso
qase.commentprobara.comment(text)Se escribe al principio de las notas del resultado, antes del error
qase.ignoreprobara.ignore()Lo mismo
qase.parameters / groupParametersprobara.parameters({ ... })Una sola llamada para ambos; el navegador se añade solo
qase.step(title, params)probara.step(title, body?, { expected, data })Con cuerpo o sin él; el anidamiento sigue el orden de las llamadas
qase.attach({ paths | content })probara.attach({ name, path | body })El nombre es obligatorio; un archivo que falta se omite con una advertencia
Un proyecto por prefijo de ID de casoprojects y el prefijo del ID de casoVarios proyectos
QASE_REPORTPROBARA_API_TOKEN y PROBARA_PROJECTEl envío se activa cuando ambos están definidos; se desactiva con enabled: false
QASE_RUN_IDPROBARA_RUN_ULID (run.ulid)Reportar en una ejecución que ya existe
El modo report y su carpeta de resultadosresultsFile y probara import resultsUn archivo JSON con lo que no se pudo enviar, enviado más tarde
Capturas buscadas en screenshotsFolderNada que configurarAdjuntas al intento exacto (attachScreenshots, activado por defecto)
El vídeo buscado en videosFoldervideo: true y attachVideosDesactivado por defecto: una subida por resultado fallido

Ambos reporters envían un resultado por intento, reportan it.skip como omitida, y reportan como omitidas las pruebas que un beforeEach fallido impidió ejecutar. Probara añade el parámetro attempt desde el segundo intento.

Función de QasePor qué no
El perfilador de red (el registrador de cy.intercept)Una tarea por petición: más ruido y coste que valor
qase.cucumberStepsLos pasos de Cucumber son cosa de un preprocesador BDD
Un perfil de reintentos (qué intentos conservar)Cada intento es un resultado; statusMapping y statusFilter son las únicas reglas que cambian o descartan uno
Hooks propios de la ejecución (beforeRunHook, afterRunHook)El plugin crea la ejecución, la envía y la cierra cuando termina la ejecución; closeRun decide si se cierra

El plugin de Allure se registra en setupNodeEvents y publica su API en el archivo de soporte, como este reporter: sustituye ambos registros y cambia el nombre de las llamadas.

Allure CypressProbaraQué cambia
allure.step(name, body)probara.step(title, body?, { expected, data })expected y data son el resultado esperado y los datos del paso del caso
stepsFromCommands (cada comando, un paso)Nada: los comandos no son pasosNombra los pasos con probara.step(); Probara guarda 200 pasos por resultado
allure.attachment(name, content, type)probara.attach({ name, body, contentType })El plugin lee un path desde la raíz del proyecto
allure.link(url, name) / allure.issue(id)probara.link(url, name?) / probara.issue(id)Una incidencia se convierte en enlace mediante issueUrlTemplate
allure.tmsprobara.link(url, name?)Un enlace normal
displayName, description, severityprobara.title(), probara.fields({ ... })Campos del caso que crea el informe
Etiquetas (labels y tags)probara.tags('smoke', 'cart')Etiquetas del caso creado
allure.parameter(name, value)probara.parameters({ name: value })El navegador se añade solo
historyIdNada: la clave es la ruta de la spec y el título completoUna clave propia renombraría cada caso que conoce la importación
El vídeo de una specvideo: true y attachVideosDesactivado por defecto: una subida por resultado fallido

No se portan: un responsable del caso (Probara no tiene ese campo), los parámetros enmascarados (se envían todos los parámetros), y las categorías, los problemas conocidos y los enlaces de defectos de Allure.

trcli es un comando, no un reporter: lee el JUnit XML de la ejecución y lo sube después de las pruebas. El reporter sustituye tanto el XML como la subida.

trcliProbara
--user / --password / --projectPROBARA_API_TOKEN (la tarjeta Cypress) y projectId
--add-run, --close-runLa ejecución se crea y se cierra sola; run.ulid reutiliza una
--milestone, --plan, --configurationrun.milestone, run.plan, run.configurations
--refsNada: una ejecución de Probara no tiene campos de referencia propios; acepta run.tags
parse_junitNada: los resultados se envían cuando termina la ejecución
-a, --assignassignFailedTo
--case-fieldsprobara.fields({ ... }) para el caso que crea el informe
--case-matcherNada: la clave de automatización es la ruta de la spec y el título completo
automation_id, un C123 en el títuloUn ID de caso en el título (SHOP-1), o probara.id('SHOP-1')
--run-idPROBARA_RUN_ULID
--result-fieldsNo se porta: Probara no tiene campos de resultado
--update-existing-cases, --update-strategyNo se porta: un informe nunca cambia un caso; cámbialo en Probara, donde se puede revisar

@probara/cypress-reporter sigue el versionado semántico. Lee el changelog antes de actualizar: cada cambio que requiere una acción por tu parte aparece ahí primero.

  • 0.x (ahora): el reporter es joven. Una versión menor (0.2.0) puede cambiar opciones, líneas del registro o valores por defecto; una versión de parche (0.1.1) solo corrige errores. Fija la versión en package.json (o conserva el lockfile) y actualiza a propósito.
  • 1.0 y posteriores: cambios incompatibles solo en una versión mayor.
  • @probara/cypress-reporter depende de @probara/core de la misma línea de versiones; instala solo el reporter y deja que traiga su core.

Cualquiera de estos necesita una versión mayor a partir de la 1.0, y una menor antes:

  • Una opción o una variable PROBARA_* eliminada o renombrada, o con un significado distinto.
  • Un valor por defecto cambiado (el cierre de ejecuciones, la creación de casos que faltan, keyIncludesFile, lo que se adjunta).
  • Un helper probara.*, el plugin (@probara/cypress-reporter/setup) o el archivo de soporte (@probara/cypress-reporter/support) eliminado, o con un comportamiento distinto.
  • Un cambio del estado con el que se envía un intento, para el mismo intento.
  • Cualquier cambio en la clave de automatización de una prueba, con keyIncludesFile activado o no. Una clave distinta desvincula la prueba de su caso: la siguiente ejecución crea uno nuevo.
  • Dejar de admitir una versión de Cypress o de Node.js que sigue teniendo soporte oficial.

Añadir una opción, un helper, una línea de registro o un archivo subido no es incompatible. Las líneas [probara] son para personas: no las analices con código.

El algoritmo de la clave es la clave de automatización v1, congelada en @probara/core y fijada por vectores de referencia: ninguna versión del reporter la cambia. Lo que añade el reporter es cómo una prueba de Cypress se convierte en las partes de la clave, del mismo modo en que probara import junit lee el informe del reporter junit de Cypress o de cypress-junit:

  • el archivo de la spec relativo al projectRoot de Cypress, cuando keyIncludesFile está activado, como el atributo file de la suite raíz del informe;
  • el título completo, los títulos de los describe y el del it unidos por un espacio, como un solo segmento, sin los IDs de caso.

Esa correspondencia también forma parte del contrato: una versión que cambia la clave de una prueba es un cambio incompatible, señalado como tal en el changelog. Para comprobar una actualización, compara lo que enviarían ambas versiones, cada una con su propio archivo de resultados (comprobar qué se enviaría). Cada clave que cambie es una prueba que recibiría un caso nuevo.

NecesitaCompatible
Cypress15.10.0 y posteriores (el rango de peer); probado en 16.1.1
Node.js22.12 y posteriores (el campo engines), para el Node.js que arranca cypress

Cypress 15.10.0 es la primera versión con Cypress.expose(), que el plugin usa para entregar sus ajustes al navegador: en un Cypress anterior, los helpers probara.* no tendrían nada que leer. El plugin se ejecuta en el Node.js que arranca cypress; el reporter, en el Node.js que trae Cypress. Cypress 15 todavía funciona con Node.js 20, y este reporter no: un proyecto con Cypress 15 y Node.js 20 tiene que actualizar antes Node.js. 0.1.0 es la primera versión: todavía no hay nada desde lo que migrar.

Relacionado: Primeros pasos · Vincular · CLI · Fuente: migrating-from-junit.md, migrating-from-qase.md, coming-from-other-tools.md, upgrade.md