# Pasos y adjuntos en Cypress

> Registra pasos anidados con probara.step(), adjunta archivos con probara.attach(), las capturas y el vídeo que graba Cypress, la salida de consola de cada prueba y los límites que se aplican.

Un resultado puede llevar pasos y archivos. Cypress no tiene pasos propios: escríbelos con
`probara.step()`. Cypress toma por sí solo una captura de pantalla de cada fallo, y el reporter la
adjunta al intento al que pertenece; `probara.attach()` es para todo lo demás.

## `probara.step()`

```js
// cypress/e2e/cart.cy.js
describe('Cart', () => {
  it('checks out', () => {
    probara.step(
      'Open the cart',
      () => {
        cy.get('.cart').click();
        probara.step('The cart holds two items', () => {
          cy.get('.cart-item').should('have.length', 2);
        });
      },
      { expected: 'The cart shows two items' },
    );

    probara.step('Pay by card', () => {
      cy.get('.pay').click();
    });
  });
});
```

| Argumento          | Qué es                                                       |
| ------------------ | ------------------------------------------------------------ |
| `title`            | Lo que hizo el paso. Es la `action` del paso en Probara.     |
| `body()`           | Los comandos de Cypress del paso. Sin él, un paso que pasó.  |
| `options.expected` | El resultado esperado, para el caso que crea el informe.     |
| `options.data`     | Los datos que usa el paso, para el caso que crea el informe. |

Los pasos aparecen bajo el resultado, anidados tal como se ejecutaron, cada uno con su estado, su
duración y su error. Los pasos más externos son también los pasos del caso que crea el informe, con
lo que declaran `expected` y `data`; los anidados en ellos pertenecen solo a su paso. Un caso
existente conserva sus propios pasos.

### Qué es un paso en Cypress

- **No devuelve nada.** `probara.step()` no es una promesa: su cuerpo encola comandos de Cypress, y
  el paso termina cuando Cypress los ha ejecutado. Nunca devuelve el resultado de su cuerpo.
- **El anidamiento sigue el orden de las llamadas.** Un `probara.step()` llamado dentro del cuerpo
  de otro es su hijo, y un archivo adjuntado dentro de un cuerpo pertenece a ese paso. Un cuerpo que
  espera (`await`) entre sus comandos los intercala con los pasos siguientes: escribe el cuerpo sin
  esperas, o divídelo en dos pasos.
- **Un comando que falla hace fallar el paso.** Una aserción dentro de un paso, o un `cy.get()` de
  algo que no existe, se reporta como un paso fallido, con el error _the step had not finished when
  the test ended_; el resultado lleva el error del comando.
- **Un cuerpo que lanza un error hace fallar la prueba.** Cypress hace fallar una prueba cuyo cuerpo
  lanza un error antes de ejecutar los comandos que ese cuerpo encoló: la prueba se reporta fallida
  con el error, y el paso en sí no.

### Los comandos no son pasos

Los comandos de Cypress no se convierten en pasos: un paso es lo que una prueba dice que hizo con
`probara.step()`, no cada comando que encoló su framework. Cada clic y cada aserción como paso
multiplicarían los pasos de un resultado, y Probara guarda 200 por resultado.

## `probara.attach()`

```js
// cypress/e2e/cart.cy.js
it('writes the cart as CSV', () => {
  probara.attach({ name: 'cart.csv', body: 'sku,qty\nA-1,2\n' });
  probara.attach({ name: 'report.png', path: 'cypress/fixtures/report.png' });
});
```

| Argumento     | Qué es                                                               |
| ------------- | -------------------------------------------------------------------- |
| `name`        | El nombre con el que el archivo aparece en Probara. Obligatorio.     |
| `body`        | El contenido: un texto, un `Uint8Array` o un `ArrayBuffer`.          |
| `path`        | Un archivo del proyecto, que lee el plugin.                          |
| `contentType` | El tipo del archivo; sin él, se deduce de la extensión de su nombre. |

- **Un cuerpo** se adjunta tal cual; los bytes los convierte el navegador y los escribe el plugin.
  La llamada no devuelve nada.
- **Una ruta** se lee desde la raíz del proyecto, como la lee `cy.readFile()`, no desde la carpeta
  de la spec. La lee el plugin, así que un archivo que falta nunca hace fallar la prueba: se omite,
  con una advertencia por ruta. La llamada devuelve la cadena del `cy.task()` que entrega la ruta:
  espérala cuando la prueba necesite el archivo adjunto antes de seguir.

### Archivos de un paso

Un archivo adjuntado dentro de un `probara.step()` pertenece a ese paso; cualquier otro pertenece al
resultado, junto a los pasos. Un nombre con extensión la conserva; un nombre sin ella toma la
extensión del archivo del que procede.

## Capturas de pantalla

Cypress toma por sí solo una captura de un intento fallido, y el reporter la adjunta al resultado de
**ese** intento, como `image/png`. No se busca nada en una carpeta: el plugin recibe cada captura de
Cypress con su ruta exacta, y el reporter lee el nombre que le dio Cypress:

| Cómo la nombra Cypress                                    | Qué es                                                                               |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `<títulos unidos por ' -- '> (failed)`                    | El primer intento fallido de una prueba                                              |
| `<títulos unidos por ' -- '> (failed) (attempt N)`        | Un reintento, desde el segundo intento                                               |
| `<títulos unidos por ' -- '> -- <hook> hook (failed) (…)` | Un `beforeEach` o `before` que falla, con el nombre del hook y de la prueba en curso |

Así cada captura llega al intento para el que se tomó, y una prueba que falla dos veces tiene dos.

| Ajuste                                           | Qué pasa                                                       |
| ------------------------------------------------ | -------------------------------------------------------------- |
| `attachScreenshots: true` (el valor por defecto) | Se adjunta la captura de cada intento fallido                  |
| `attachScreenshots: false`                       | No se adjunta ninguna; Cypress las sigue tomando donde siempre |
| Sin plugin (`setupNodeEvents`)                   | No se adjunta ninguna: solo el plugin recibe las capturas      |

No se adjuntan, a propósito:

- **Una captura que tomaste tú**, como `cy.screenshot('my-name')`: su nombre no coincide con ningún
  intento fallido, así que se omite y se nombra una vez con `PROBARA_DEBUG`. Para conservarla,
  adjúntala con `probara.attach()`.
- **Una captura de un intento que no falló**: solo se adjuntan los fallos.

## El vídeo de una spec

Con `video: true` en la configuración de Cypress y `attachVideos: true` en las opciones del
reporter, el vídeo de una spec se adjunta a **cada resultado fallido de esa spec** (también a uno
bloqueado), con el nombre del archivo de la spec (`cart.cy.js.mp4`), como `video/mp4`. Una spec sin
resultados fallidos no envía vídeo. Necesita el plugin, que es quien recibe el vídeo de Cypress.

`attachVideos` está desactivado por defecto por su coste: una subida por cada resultado fallido de la
spec, y los vídeos pesan mucho.

## Salida de consola

`captureOutput: true` (`PROBARA_CAPTURE_OUTPUT`, desactivado por defecto) adjunta lo que cada prueba
escribe en la consola del navegador, como dos archivos de su resultado:

| Flujo  | Qué entra                                      | Se adjunta como             |
| ------ | ---------------------------------------------- | --------------------------- |
| stdout | `console.log`, `console.info`, `console.debug` | `stdout.log` (`text/plain`) |
| stderr | `console.warn`, `console.error`                | `stderr.log` (`text/plain`) |

La consola del navegador lo sigue mostrando todo, se capture o no. Cada flujo se corta en 32 MiB, y
el adjunto termina entonces con:

```text
[probara] The output of this test was cut here: an attachment holds at most 32 MiB
```

Qué no se captura:

- Cualquier otro método de la consola (`console.table`, `console.dir`, `console.group`,
  `console.count`, `console.time`).
- Un método de la consola que la prueba sustituyó.
- Lo que se escribe fuera de una prueba.
- Nada, sin el archivo de soporte: la captura la instala ese archivo.

## Límites y qué se omite

Probara somete cada adjunto a estos límites; el reporter omite un archivo en lugar de hacer fallar un
resultado, y nombra cada archivo omitido en el registro de la ejecución:

| Límite                                             | Qué pasa                                                                                               |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| 20 archivos por resultado                          | Los adjuntos que pasan de 20 en un resultado se omiten                                                 |
| 32 MiB por archivo                                 | La salida de consola capturada se corta en este tamaño, con la línea de arriba                         |
| 10 MiB por imagen                                  | Una imagen mayor se omite                                                                              |
| 8192 px por lado de una imagen                     | Una imagen mayor se omite (una captura de página completa de una página larga lo supera con facilidad) |
| Ejecutables y scripts por tipo de contenido        | Un tipo rechazado (`application/x-msdownload`, `application/x-sh`, `application/x-bat`, …) se omite    |
| 255 caracteres en el nombre de archivo guardado    | Un nombre más largo se recorta                                                                         |
| 200 pasos por resultado, 10 niveles de profundidad | El límite de los pasos de un resultado                                                                 |

`uploadAttachments: false` (`PROBARA_UPLOAD_ATTACHMENTS=false`) no sube ningún archivo: los pasos,
los enlaces y los parámetros se siguen enviando.

## Cuando faltan pasos o archivos

| Lo que ves                                                                | Por qué                                                                                                              |
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Ningún paso, ningún archivo, ningún efecto de `probara.*`                 | Falta el plugin o el archivo de soporte ([registro](https://docs.probara.net/es/developers/ci-integrations/cypress/configuration/#registro)) |
| Resultados, pero sin captura                                              | Sin plugin, `attachScreenshots: false`, o la captura era tuya                                                        |
| `probara.attach() could not read "<path>" (<reason>): it is not attached` | El archivo de un `path` no existe o no se puede leer                                                                 |
| `probara.attach() takes { name, path } or { name, body }`                 | Un argumento incorrecto; la llamada se ignora y la prueba sigue                                                      |
| `probara.step() takes a function as its body`                             | El cuerpo no era una función                                                                                         |
| `Skipped an attachment: <reason>`                                         | Un archivo que supera un [límite](#límites-y-qué-se-omite)                                                           |

Cada una de las demás advertencias está en
[solución de problemas](https://docs.probara.net/es/developers/ci-integrations/cypress/troubleshooting/#los-helpers-no-hicieron-nada).

Relacionado: [Metadatos y enlaces](https://docs.probara.net/es/developers/ci-integrations/cypress/metadata/) ·
[Configuración](https://docs.probara.net/es/developers/ci-integrations/cypress/configuration/#captureoutput) ·
[Solución de problemas](https://docs.probara.net/es/developers/ci-integrations/cypress/troubleshooting/) · Fuente:
[steps.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/steps.md),
[attachments.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/attachments.md),
[specs.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/cypress-reporter/docs/specs.md)
