# Metadatos y enlaces de pruebas de Jest

> Los helpers probara.* de @probara/jest-reporter — título, suite, etiquetas, campos, parámetros, comentarios, ignorar un intento, enlaces e incidencias — y dónde funcionan.

`probara` le da al reporter más información sobre una prueba, desde el cuerpo de la prueba o desde un
hook `beforeEach` o `afterEach`. Impórtalo con `require` (o `import`) desde el paquete del reporter:

```js
// tests/payments.test.js
const { probara } = require('@probara/jest-reporter');

test('pays with a card', () => {
  probara.title('Pays with a saved card').suite(['Payments', 'Cards']).tags('smoke');
});
```

En un archivo de prueba compilado desde módulos ES (Babel, `ts-jest`),
`import { probara } from '@probara/jest-reporter'` da los mismos helpers. El paquete incluye sus
tipos, así que las pruebas en TypeScript también los tienen.

| Helper                                | Qué hace                                                                                                                  | Llamadas repetidas         |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| `id(id \| ids)`                       | Vincula casos existentes ([vincular](https://docs.probara.net/es/developers/ci-integrations/jest/linking/))                                       | Se suman                   |
| `title(text)`                         | Título del caso que crea el informe                                                                                       | Gana la última             |
| `suite(title \| titles)`              | Ruta de suites del caso que crea el informe                                                                               | Gana la última             |
| `comment(text)`                       | Un comentario, al principio de las notas del resultado, antes del error                                                   | Gana la última             |
| `ignore()`                            | Omite este intento: no se reporta                                                                                         | —                          |
| `tags(...names)`                      | Etiquetas del caso que crea el informe                                                                                    | Se suman, cada una una vez |
| `fields(record)`                      | Campos del caso que crea el informe: campos de sistema, campos personalizados, `description`                              | Se combinan por nombre     |
| `parameters(record)`                  | Parámetros del resultado, que se muestran con él                                                                          | Se combinan por nombre     |
| `link(url, name?)`, `issue(id)`       | Enlaces del resultado ([enlaces e incidencias](#enlaces-e-incidencias))                                                   | Se suman                   |
| `attach({ name, path \| body, ... })` | Adjunta un archivo ([adjuntos](https://docs.probara.net/es/developers/ci-integrations/jest/steps-and-attachments/#probaraattach))                 | Cada una adjunta           |
| `step(title, body?, options?)`        | Un paso del resultado, y del caso nuevo ([pasos](https://docs.probara.net/es/developers/ci-integrations/jest/steps-and-attachments/#probarastep)) | Cada una es un paso        |

Los helpers que no devuelven otra cosa devuelven `probara`, así que las llamadas se encadenan. Cada
una se aplica solo al intento en curso: un reintento empieza vacío.

## Solo casos creados

`title`, `suite`, `tags`, `fields` y los pasos del caso describen el caso que **crea** un informe, la
primera vez que se reporta una prueba. Un caso existente nunca cambia: Probara conserva lo que las
personas escribieron en él. La clave de automatización tampoco cambia nunca
([claves](https://docs.probara.net/es/developers/ci-integrations/jest/linking/#claves-de-automatización)), así que un título
nuevo sigue encontrando el mismo caso.

```js
// tests/payments.test.js
const { probara } = require('@probara/jest-reporter');

test('pays', () => {
  probara
    .title('Pays with a saved card')
    .suite(['Payments', 'Cards'])
    .tags('smoke', 'payments')
    .fields({
      description: 'A returning customer pays with the card saved in their profile.',
      severity: 'critical',
      priority: 'high',
      'Risk area': 'Checkout',
    });
});
```

```json
[
  {
    "automationKey": "tests/payments.test.js > pays",
    "title": "Pays with a saved card",
    "suitePath": ["Payments", "Cards"],
    "case": {
      "description": "A returning customer pays with the card saved in their profile.",
      "tags": ["smoke", "payments"],
      "fields": { "severity": "critical", "priority": "high", "Risk area": "Checkout" }
    }
  }
]
```

### Campos

`fields()` acepta nombres y valores (los números y los booleanos se convierten en texto):

| Nombre                                                                    | Qué define                                                  |
| ------------------------------------------------------------------------- | ----------------------------------------------------------- |
| `description`                                                             | La descripción del caso                                     |
| `severity`, `priority`, `type`, `layer`, `behavior`, `status`, `is_flaky` | Los campos de sistema, por el nombre de una opción (`high`) |
| `preconditions`, `postconditions`                                         | Los campos de texto de sistema                              |
| Cualquier otro nombre, como `'Risk area'`                                 | El campo personalizado con ese nombre                       |

Probara resuelve los nombres y las opciones al crear el caso. Un campo o una opción que no conoce se
omite y se registra como advertencia; el resultado se registra igualmente. Un campo con el valor
vacío se omite sin advertencia.

### Título y suite

El título de un caso creado es el título de la prueba (sin los IDs de caso), salvo que `title()` diga
otro. Su suite es el archivo de prueba (`tests/payments.test.js`) o, con `keyIncludesFile: false`, el
`describe` más externo, salvo que `suite()` indique una: `suite('Payments')`, o
`suite(['Payments', 'Cards'])` para suites anidadas, que se crean cuando hace falta bajo
`suiteUlid`.

## Comentario

`comment()` escribe una línea al principio de las notas del resultado, antes del error y su traza:

```js
// tests/search.test.js
const { probara } = require('@probara/jest-reporter');

test('searches the catalog', () => {
  probara.comment('Ran against the staging catalog');
});
```

```json
[
  {
    "automationKey": "tests/search.test.js > searches the catalog",
    "notes": "Ran against the staging catalog"
  }
]
```

Cuando el intento falla, su error va a continuación del comentario en las mismas notas, sin los
colores de la terminal: el comentario nunca oculta el error.

## Parámetros

`parameters()` registra los valores con los que se ejecutó un intento, que se muestran con su
resultado, como el usuario o el conjunto de datos de una prueba basada en datos. Nunca forman parte
de la clave: la prueba es un solo caso sean cuales sean sus parámetros. Cuando el caso declara un parámetro con el mismo nombre, el resultado se registra en el caso de ejecución con esos valores. Un parámetro que el caso no declara se queda en el resultado solo para mostrarlo. Un caso que un reporte crea toma sus valores como parámetro `Examples` cuando al menos dos de sus resultados reportan los mismos nombres con valores distintos.

```js
// tests/users.test.js
const { probara } = require('@probara/jest-reporter');

test.each(['admin', 'viewer'])('opens the dashboard as %s', (role) => {
  probara.parameters({ role, seats: 5 });
});
```

```json
[
  {
    "automationKey": "tests/users.test.js > opens the dashboard as admin",
    "parameters": { "role": "admin", "seats": "5" }
  },
  {
    "automationKey": "tests/users.test.js > opens the dashboard as viewer",
    "parameters": { "role": "viewer", "seats": "5" }
  }
]
```

Un título de `test.each` que contiene el valor (como arriba) es un caso por valor, que es como Jest
nombra sus filas. Mantén un marcador en el título: las filas con el mismo nombre en un archivo
comparten una clave, y lo que dijeron sus helpers se omite
([nombres](https://docs.probara.net/es/developers/ci-integrations/jest/linking/#nombres-tal-como-los-escribe-jest-junit)).

## Ignorar un intento

`ignore()` omite el intento en curso: se sigue ejecutando, y Jest lo reporta, pero Probara no lo
recibe. El recuento del registro dice cuántos se omitieron.

```js
// tests/experimental.test.js
const { probara } = require('@probara/jest-reporter');

test('tries the new checkout', () => {
  probara.ignore();
});

test('pays', () => {});
```

```text
$ npx jest
[probara] Sending 1 result of 1 test (1 passed, 0 failed, 0 skipped, 0 blocked); 1 ignored with probara.ignore()
[probara] Recorded 1 result (1 new case, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1
```

## Enlaces e incidencias

Un resultado puede llevar enlaces, que se muestran con él en Probara: el build que lo ejecutó, la
página que probó, las incidencias de tu gestor a las que se refiere.

### `probara.link()`

`probara.link(url, name?)` acepta una URL `http` o `https` absoluta y un nombre opcional, que se
muestra en lugar de la URL:

```js
// tests/search.test.js
const { probara } = require('@probara/jest-reporter');

test('searches the catalog', () => {
  probara
    .link('https://shop.example.com/search?q=boots', 'Search page')
    .link('https://ci.example.com/builds/1042');
});
```

```json
[
  {
    "automationKey": "tests/search.test.js > searches the catalog",
    "links": [
      { "url": "https://shop.example.com/search?q=boots", "name": "Search page" },
      { "url": "https://ci.example.com/builds/1042" }
    ]
  }
]
```

### `probara.issue()` e `issueUrlTemplate`

`probara.issue(id)` nombra una incidencia de tu gestor por su ID. Con `issueUrlTemplate`
(`PROBARA_ISSUE_URL_TEMPLATE`), una URL con `%s` donde va el ID, se convierte en un enlace del
resultado, con el ID como nombre:

```js
reporters: [
  'default',
  ['@probara/jest-reporter', { issueUrlTemplate: 'https://jira.example.com/browse/%s' }],
],
```

```js
// tests/checkout.test.js
const { probara } = require('@probara/jest-reporter');

test('rounds the total', () => {
  probara.issue('PAY-7').issue('PAY 12');
});
```

```json
[
  {
    "automationKey": "tests/checkout.test.js > rounds the total",
    "links": [
      { "url": "https://jira.example.com/browse/PAY-7", "name": "PAY-7" },
      { "url": "https://jira.example.com/browse/PAY%2012", "name": "PAY 12" }
    ]
  }
]
```

- El ID entra en la plantilla codificado para URL (`PAY 12` se convierte en `PAY%2012`), en lugar del
  primer `%s`.
- La plantilla es una URL `http` o `https` con `%s`; cualquier otro valor desactiva el envío con un
  error que nombra `issueUrlTemplate`.
- Sin plantilla, las incidencias se omiten, y una advertencia lo indica: el resultado se registra sin
  ellas.

```text
$ npx jest
[probara] Dropped the issues of probara.issue(): no issueUrlTemplate turns their ids into links (first seen in "rounds the total"; repeats are logged at debug)
[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-1
```

### Reglas de los enlaces

| Regla                                             | Qué pasa                                            |
| ------------------------------------------------- | --------------------------------------------------- |
| Enlaces e incidencias de un intento               | Se envían en el orden de las llamadas, todos juntos |
| Una URL que no es una URL `http`/`https` absoluta | Se omite, con una advertencia                       |
| Una URL de más de 2048 caracteres                 | Se omite, con una advertencia                       |
| Un nombre de más de 255 caracteres                | Se recorta a 255 caracteres, con una advertencia    |
| Más de 20 enlaces en un resultado                 | Se envían los 20 primeros, con una advertencia      |
| Un reintento                                      | Empieza sin enlaces: cada intento envía los suyos   |

Los enlaces pertenecen al resultado, no al caso: un caso existente nunca cambia, y cada resultado
conserva los enlaces que añadió su intento. Para vincular el propio caso a una incidencia de Jira,
consulta [Trazabilidad con Jira](https://docs.probara.net/es/guides/integrations/jira-traceability/).

## Dónde llamar a los helpers

| Dónde                                                                     | Qué pasa                                                                  |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| El cuerpo de la prueba, `beforeEach`, `afterEach`                         | Se aplica al intento en curso                                             |
| Una función auxiliar o un módulo al que llama la prueba                   | Lo mismo: los helpers encuentran por sí solos la prueba en curso          |
| El ámbito del módulo, el cuerpo de un `describe`, `beforeAll`, `afterAll` | Se ignora, con una advertencia: ahí no se ejecuta ninguna prueba concreta |
| Una prueba `test.concurrent`                                              | Se aplica a esa prueba                                                    |

Un helper nunca lanza un error dentro de la prueba. Un argumento incorrecto, o una llamada cuando no
se está ejecutando ninguna prueba, es una advertencia `[probara]` en el registro del reporter, que
nombra el archivo de prueba, y la llamada se ignora:

```js
// tests/orders.test.js
const { probara } = require('@probara/jest-reporter');

beforeAll(() => {
  probara.tags('orders');
});

test('lists the orders', () => {
  probara.tags('orders');
});
```

```text
$ npx jest
[probara] probara.tags() only works while a test runs (in a test, or a beforeEach or afterEach hook) (first seen in tests/orders.test.js; repeats are logged at debug)
[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-1
```

## En cada worker y cada entorno

Los helpers funcionan dondequiera que Jest ejecute una prueba: en sus procesos worker y en banda
(`--runInBand`), en los entornos de prueba `node` y `jsdom`, en modo watch, y en archivos de prueba
escritos con `import`. No hay que configurar nada para ellos: el reporter indica a los procesos de
prueba dónde escribir antes de que empiecen.

```js
// jest.config.js (excerpt)
testEnvironment: 'jsdom',
```

```js
// tests/banner.test.js
const { probara } = require('@probara/jest-reporter');

test('shows the banner', () => {
  document.body.innerHTML = '<p role="banner">Free shipping</p>';
  probara.parameters({ locale: document.documentElement.lang || 'en' });
});
```

```json
[{ "automationKey": "tests/banner.test.js > shows the banner", "parameters": { "locale": "en" } }]
```

### Cómo viajan los metadatos

Jest ejecuta las pruebas en procesos worker y el reporter en su proceso principal. Al empezar la
ejecución, el reporter crea una carpeta en el directorio temporal del sistema y se la indica a los
procesos de prueba; cada llamada `probara.*` añade ahí una línea, identificada por el archivo de
prueba, el nombre completo de la prueba y su intento, que los helpers leen del propio estado de Jest
(jest-circus). `probara.attach()` copia su archivo ahí en el momento. El reporter lee las líneas
cuando termina cada archivo, y elimina la carpeta cuando termina `jest`. Sin el reporter, cada helper
no hace nada (y `probara.step()` sigue ejecutando su cuerpo), así que las pruebas siguen pasando donde
el reporter no está registrado.

Límites conocidos:

- **Solo jest-circus.** Con `testRunner: 'jest-jasmine2'` no se registra ninguna llamada, y una
  advertencia lo indica.
- **`jest.mock('fs')`** sustituye el sistema de archivos del archivo de prueba, que es con lo que
  escriben los helpers: sus llamadas en ese archivo se pierden, sin aviso. Simula solo los módulos que
  importa tu código, o usa `jest.spyOn` sobre las funciones a las que llama.
- **Dos pruebas con el mismo nombre completo** en un archivo: lo que dijeron sus llamadas se omite,
  con una advertencia.
- **Jest 30.0 a 30.4 y los reintentos de `test.concurrent`**: esas versiones no indican qué intento
  de una prueba concurrente se está ejecutando, así que las llamadas de un reintento de una prueba
  `test.concurrent` van a su primer intento. Jest 29 nunca reintenta pruebas concurrentes, y 30.5 sí
  lo indica.

Relacionado: [Pasos y adjuntos](https://docs.probara.net/es/developers/ci-integrations/jest/steps-and-attachments/) ·
[Vincular](https://docs.probara.net/es/developers/ci-integrations/jest/linking/) ·
[Migrar desde Qase](https://docs.probara.net/es/developers/ci-integrations/jest/migrating/#desde-qase) · Fuente:
[metadata.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/jest-reporter/docs/metadata.md),
[links.md](https://github.com/cynch-me/probara-sdk/blob/main/packages/jest-reporter/docs/links.md)
