# Migrar al reporter de Cypress

> Pasa a @probara/cypress-reporter desde la importación JUnit, Qase, Allure Cypress o trcli de TestRail conservando tus casos — y cómo actualizar el reporter con seguridad.

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.

```js
// 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);
    },
  },
});
```

```js
// 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](https://docs.probara.net/es/developers/ci-integrations/cypress/configuration/#con-otros-plugins).

| Vienes de                                                                  | Ve a                                                |
| -------------------------------------------------------------------------- | --------------------------------------------------- |
| El reporter `junit` de Cypress o cypress-junit, con `probara import junit` | [La importación JUnit](#desde-la-importación-junit) |
| El reporter de Qase para Cypress                                           | [Qase](#desde-qase)                                 |
| `allure-cypress`                                                           | [Allure Cypress](#desde-allure-cypress)             |
| JUnit XML y `trcli parse_junit`                                            | [TestRail](#desde-testrail)                         |

## Desde la importación JUnit

Si tu pipeline escribe JUnit XML con el reporter `junit` integrado en Cypress o con
[cypress-junit](https://www.npmjs.com/package/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.

```js
// 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`](https://docs.probara.net/es/developers/ci-integrations/cypress/configuration/#con-cypress-multi-reporters).
2. [Comprueba las claves](#comprueba-las-claves-antes-de-cambiar) 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 JUnit                                                                | Ajuste del reporter                                    |
| ------------------------------------------------------------------------------- | ------------------------------------------------------ |
| Escrito con las opciones por defecto, con la spec en el `file` de su suite raíz | Nada: `keyIncludesFile: true` es el valor por defecto  |
| Escrito sin ese atributo `file`                                                 | `keyIncludesFile: 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.

### Comprueba las claves antes de cambiar

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.

```bash
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
```

```text
$ 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](#qué-cambia-respecto-a-la-importación-junit)). 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.

### En CI

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

```yaml
- 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.

```yaml
- 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

| Cypress                                     | `probara import junit`           | El reporter                                                                 |
| ------------------------------------------- | -------------------------------- | --------------------------------------------------------------------------- |
| Una prueba que falla y pasa en un reintento | Un 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 intentos  | Un resultado: el último fallo    | Un resultado por intento                                                    |
| Un hook que falla en todos los intentos     | Solo el fallo del hook           | El intento reintentado de la prueba, y el fallo del hook que nombra Cypress |
| Las pruebas que ese hook impidió ejecutar   | Nada: no dejaron ningún testcase | Un resultado omitido cada una                                               |
| Suite de un caso creado                     | Solo la spec                     | La 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.

## Desde Qase

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.

### Vincular por ID de caso

```js
// 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](https://docs.probara.net/es/developers/ci-integrations/cypress/linking/)).

### Los nombres, uno junto a otro

| En una batería con Qase                              | En una batería con Probara                        | Qué cambia                                                                                       |
| ---------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `(Qase ID: 12)` en el título de un `it` o `describe` | `SHOP-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.fields`                                        | `probara.fields({ ... })`                         | Solo tiene efecto cuando el informe crea un caso                                                 |
| `qase.comment`                                       | `probara.comment(text)`                           | Se escribe al principio de las notas del resultado, antes del error                              |
| `qase.ignore`                                        | `probara.ignore()`                                | Lo mismo                                                                                         |
| `qase.parameters` / `groupParameters`                | `probara.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 caso                | `projects` y el prefijo del ID de caso            | [Varios proyectos](https://docs.probara.net/es/developers/ci-integrations/cypress/sharding/#varios-proyectos-de-probara) |
| `QASE_REPORT`                                        | `PROBARA_API_TOKEN` y `PROBARA_PROJECT`           | El envío se activa cuando ambos están definidos; se desactiva con `enabled: false`               |
| `QASE_RUN_ID`                                        | `PROBARA_RUN_ULID` (`run.ulid`)                   | Reportar en una ejecución que ya existe                                                          |
| El modo report y su carpeta de resultados            | `resultsFile` y `probara import results`          | Un archivo JSON con lo que no se pudo enviar, enviado más tarde                                  |
| Capturas buscadas en `screenshotsFolder`             | Nada que configurar                               | Adjuntas al intento exacto (`attachScreenshots`, activado por defecto)                           |
| El vídeo buscado en `videosFolder`                   | `video: true` y `attachVideos`                    | Desactivado 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.

### Lo que no se porta de Qase

| Función de Qase                                                 | Por qué no                                                                                                       |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| El perfilador de red (el registrador de `cy.intercept`)         | Una tarea por petición: más ruido y coste que valor                                                              |
| `qase.cucumberSteps`                                            | Los 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    |

## Desde Allure Cypress

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 Cypress                                | Probara                                                   | Qué 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 pasos                           | Nombra 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.tms`                                  | `probara.link(url, name?)`                                | Un enlace normal                                                              |
| `displayName`, `description`, `severity`      | `probara.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                                                    |
| `historyId`                                   | Nada: la clave es la ruta de la spec y el título completo | Una clave propia renombraría cada caso que conoce la importación              |
| El vídeo de una spec                          | `video: true` y `attachVideos`                            | Desactivado 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.

## Desde TestRail

`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.

| trcli                                          | Probara                                                                                   |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `--user` / `--password` / `--project`          | `PROBARA_API_TOKEN` (la tarjeta **Cypress**) y `projectId`                                |
| `--add-run`, `--close-run`                     | La ejecución se crea y se cierra sola; `run.ulid` reutiliza una                           |
| `--milestone`, `--plan`, `--configuration`     | `run.milestone`, `run.plan`, `run.configurations`                                         |
| `--refs`                                       | Nada: una ejecución de Probara no tiene campos de referencia propios; acepta `run.tags`   |
| `parse_junit`                                  | Nada: los resultados se envían cuando termina la ejecución                                |
| `-a`, `--assign`                               | `assignFailedTo`                                                                          |
| `--case-fields`                                | `probara.fields({ ... })` para el caso que crea el informe                                |
| `--case-matcher`                               | Nada: la clave de automatización es la ruta de la spec y el título completo               |
| `automation_id`, un `C123` en el título        | Un ID de caso en el título (`SHOP-1`), o `probara.id('SHOP-1')`                           |
| `--run-id`                                     | `PROBARA_RUN_ULID`                                                                        |
| `--result-fields`                              | No se porta: Probara no tiene campos de resultado                                         |
| `--update-existing-cases`, `--update-strategy` | No se porta: un informe nunca cambia un caso; cámbialo en Probara, donde se puede revisar |

## Actualizar el reporter

`@probara/cypress-reporter` sigue el [versionado semántico](https://semver.org). Lee el
[changelog](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/CHANGELOG.md)
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.

### Qué es un cambio incompatible

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 contrato de la clave de automatización

El algoritmo de la clave es la
[clave de automatización v1](https://github.com/cynch-me/probara-sdk/blob/main/packages/core/README.md#the-automation-key-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](https://docs.probara.net/es/developers/ci-integrations/cypress/troubleshooting/#comprobar-qué-se-enviaría)).
Cada clave que cambie es una prueba que recibiría un caso nuevo.

### Versiones de Cypress y de Node.js

| Necesita | Compatible                                                                      |
| -------- | ------------------------------------------------------------------------------- |
| Cypress  | 15.10.0 y posteriores (el rango de peer); probado en 16.1.1                     |
| Node.js  | 22.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](https://docs.probara.net/es/developers/ci-integrations/cypress/) ·
[Vincular](https://docs.probara.net/es/developers/ci-integrations/cypress/linking/) · [CLI](https://docs.probara.net/es/developers/cli/) · Fuente:
[migrating-from-junit.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/migrating-from-junit.md),
[migrating-from-qase.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/migrating-from-qase.md),
[coming-from-other-tools.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/coming-from-other-tools.md),
[upgrade.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/upgrade.md)
