# API de matriz de cobertura

> Obtén el último resultado por caso de prueba × entorno de un proyecto en la API para integradores.

El endpoint de matriz de cobertura devuelve el **estado del resultado más reciente** para cada caso de prueba de un proyecto, desglosado por entorno. Cada fila representa un caso de prueba; cada celda dentro de la fila representa el resultado más reciente registrado para ese caso en uno de los entornos del proyecto.

El endpoint es **de solo lectura** — no emite eventos de auditoría ni realiza cambios de estado.

Todas las peticiones requieren una sesión autenticada (token de API o cookie) con membresía mínima de `viewer` en la organización del proyecto. Un `projectId` que pertenezca a otra organización devuelve `404 not_found`.

## Obtener la matriz de cobertura

`GET /api/v1/projects/{projectId}/coverage-matrix`

`{projectId}` es el **código** del proyecto (por ejemplo `ACME`).

### Parámetros de consulta

| Parámetro   | Por defecto | Notas                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ----------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `page`      | `1`         | Número de página (base 1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `pageSize`  | `50`        | Filas por página (mínimo `1`, máximo `200`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `suiteUlid` | —           | Lista opcional de ULIDs de suite, separados por comas. Cuando se indica, solo se devuelven los casos de prueba que pertenezcan a alguna de las suites listadas (semántica OR). Un único ULID se comporta de forma idéntica al comportamiento anterior. Los ULIDs desconocidos o de otro proyecto se ignoran silenciosamente; si todos los ULIDs son desconocidos, el resultado es una página vacía con `total = 0`. Un ULID con formato inválido (no es un Crockford base32 de 26 caracteres válido) devuelve `422 validation_failed`. |
| `status`    | —           | Filtro opcional por estado derivado más reciente, separado por comas. Valores aceptados: `passed`, `failed`, `blocked`, `skipped`, `untested`, `none`. `none` selecciona las filas con al menos una celda vacía (un caso nunca ejecutado en ningún entorno). Los valores se combinan con OR. Un token desconocido devuelve `422 validation_failed`.                                                                                                                                                                                    |
| `q`         | —           | Consulta de búsqueda de texto opcional. Cuando no está vacío (tras eliminar espacios), restringe las filas a los casos cuyos campos de texto (seleccionados por `searchBy`) contengan `q` como subcadena sin distinción de mayúsculas. Los caracteres `%` y `_` en `q` se tratan literalmente. Un valor vacío o compuesto solo de espacios se considera ausente (sin filtro de texto).                                                                                                                                                 |
| `searchBy`  | `all`       | Controla qué campo se busca cuando `q` no está vacío. Valores aceptados: `all` (por defecto), `title`, `id`. Consulta la tabla de [valores de searchBy](#valores-de-searchby). Un valor desconocido devuelve `422 validation_failed`.                                                                                                                                                                                                                                                                                                  |

### Respuesta

`200` con la siguiente forma:

```json
{
  "columns": [ ... ],
  "rows": {
    "items": [ ... ],
    "page": 1,
    "pageSize": 50,
    "total": 120
  }
}
```

#### `columns`

Un array de objetos de entorno, uno por cada entorno activo del proyecto, en orden de creación. Son los encabezados de columna de la matriz.

| Campo           | Tipo          | Notas                                                  |
| --------------- | ------------- | ------------------------------------------------------ |
| `environmentId` | string (ULID) | El ULID del entorno                                    |
| `name`          | string        | Nombre para mostrar (por ejemplo `Staging`)            |
| `slug`          | string        | Identificador seguro para URLs (por ejemplo `staging`) |

Los entornos eliminados de forma lógica nunca se incluyen.

#### `rows.items`

Un array paginado de filas de casos de prueba. Cada fila contiene los siguientes campos:

| Campo        | Tipo           | Notas                                                                                   |
| ------------ | -------------- | --------------------------------------------------------------------------------------- |
| `testCaseId` | string (ULID)  | El ULID del caso de prueba                                                              |
| `caseNumber` | number         | Número de caso legible dentro del proyecto                                              |
| `title`      | string         | Título del caso de prueba                                                               |
| `suite`      | object \| null | La suite a la que pertenece el caso (`{ ulid, name }`), o `null` si no tiene asignación |
| `cells`      | array          | Una celda por columna, en el mismo orden que `columns`                                  |

Cada entrada de `cells`:

| Campo           | Tipo                  | Notas                                                                                                    |
| --------------- | --------------------- | -------------------------------------------------------------------------------------------------------- |
| `environmentId` | string (ULID)         | Corresponde al `columns[i].environmentId` equivalente                                                    |
| `status`        | string \| null        | Estado del resultado más reciente para este caso en este entorno, o `null` si no existe ningún resultado |
| `executedAt`    | number \| null        | Milisegundos desde epoch Unix del resultado más reciente, o `null`                                       |
| `runUlid`       | string (ULID) \| null | La ejecución que produjo el resultado más reciente, o `null`                                             |

Un `status` `null` significa que el caso de prueba nunca se ejecutó en ese entorno — es una **celda vacía**, distinta de un resultado con estado `untested`. `cells.length` siempre es igual a `columns.length`.

### Valores de estado

| Valor      | Significado                                                                     |
| ---------- | ------------------------------------------------------------------------------- |
| `passed`   | El resultado más reciente es satisfactorio                                      |
| `failed`   | El resultado más reciente es fallido                                            |
| `blocked`  | El resultado más reciente está bloqueado                                        |
| `skipped`  | El resultado más reciente fue omitido                                           |
| `untested` | El caso fue marcado explícitamente como no probado en el resultado más reciente |
| `null`     | No hay ningún resultado registrado en este entorno (celda vacía)                |

### Valores de searchBy

| Valor               | Columnas buscadas                                                       |
| ------------------- | ----------------------------------------------------------------------- |
| `all` (por defecto) | `title` del caso **o** ID visible (`#<caseNumber>`) — combinados con OR |
| `title`             | Solo el `title` del caso                                                |
| `id`                | Solo el ID visible — el formato `#<caseNumber>` que aparece en la UI    |

Cuando `q` está ausente o vacío, `searchBy` no tiene efecto.

`total` en la respuesta siempre refleja el conteo de filas tras aplicar **todos** los filtros activos (suite + estado + texto).

### Desempate

Cuando dos resultados para el mismo par `(caso de prueba, entorno)` comparten la misma marca de tiempo `executedAt`, prevalece el resultado con el ID interno mayor.

Los resultados de ejecuciones **sin entorno asignado** (`environment_id IS NULL`) nunca se incluyen en ninguna celda.

### Errores

| Estado | Código              | Condición                                                                                                                           |
| ------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `404`  | `not_found`         | `projectId` no existe o pertenece a otra organización                                                                               |
| `422`  | `validation_failed` | `pageSize` fuera de rango, token de `status` desconocido, ULID con formato inválido en `suiteUlid`, valor de `searchBy` desconocido |

### Ejemplos

Filtrar por dos suites y buscar por título:

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/projects/ACME/coverage-matrix?suiteUlid=01JAAAA...,01JBBBB...&q=login&searchBy=title"
```

Filtrar por estado con paginación:

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  "https://app.probara.net/api/v1/projects/ACME/coverage-matrix?pageSize=20&status=failed,none"
```

Fragmento de respuesta:

```json
{
  "columns": [
    { "environmentId": "01JAAAA...", "name": "Staging", "slug": "staging" },
    { "environmentId": "01JBBBB...", "name": "Production", "slug": "production" }
  ],
  "rows": {
    "items": [
      {
        "testCaseId": "01JCCCC...",
        "caseNumber": 1,
        "title": "Inicio de sesión con credenciales válidas",
        "suite": { "ulid": "01JDDDD...", "name": "Autenticación" },
        "cells": [
          {
            "environmentId": "01JAAAA...",
            "status": "failed",
            "executedAt": 1718700000000,
            "runUlid": "01JEEEE..."
          },
          { "environmentId": "01JBBBB...", "status": null, "executedAt": null, "runUlid": null }
        ]
      }
    ],
    "page": 1,
    "pageSize": 20,
    "total": 3
  }
}
```

## Páginas relacionadas

- [API de entornos](https://docs.probara.net/es/developers/api/environments/) — lista los entornos que aparecen como columnas en la matriz.
- [Guía de la matriz de cobertura](https://docs.probara.net/es/guides/coverage-matrix/) — explicación de la pantalla Coverage para usuarios.
