# API de importación de casos de prueba

> Importa casos de prueba desde una exportación de Probara, Qase o TestRail, o desde un archivo Gherkin .feature, mediante la API para integradores — la reimportación de Probara conserva la fidelidad completa.

Los endpoints de importación cargan un archivo exportado y luego lo confirman directamente en un proyecto — no hay paso de vista previa ni de simulación. Una confirmación exitosa crea (o reemplaza) casos de prueba y suites en una sola petición; cualquier fila que no se pudo importar se reporta individualmente, y el resto del archivo se importa igual.

**Probara es la plataforma de reimportación predeterminada.** Reimportar un archivo que esta API exportó previamente (ver la [API de exportación](https://docs.probara.net/es/developers/api/export/)) es el camino sin configuración: las exportaciones JSON, XML, CSV y XLSX pueden reimportarse cada una, y la importación conserva la **fidelidad completa**. También se aceptan exportaciones de Qase y TestRail, con una superficie de mapeo de campos más reducida (ver abajo). También se acepta un archivo Gherkin `.feature` como `gherkin_feature`, de un archivo por importación (ver [Archivos Gherkin `.feature`](#archivos-gherkin-feature)).

Todas las peticiones requieren autenticación (token de API Bearer o cookie de sesión) con el permiso de importación/exportación (que tienen `owner`/`admin`/`member`). Los usuarios con rol `viewer` reciben `403 forbidden`.

## Cargar el archivo

`POST /api/v1/projects/{projectId}/imports:stage`

`{projectId}` es el **código** del proyecto (por ejemplo `ACME`). El cuerpo de la petición es `multipart/form-data` con una única parte `file` que lleva el archivo exportado.

### Respuesta

`200` con:

```json
{ "uploadUlid": "01J...", "byteSize": 4821, "filename": "acme-export.json" }
```

`uploadUlid` identifica el archivo cargado para la llamada de confirmación de abajo. Los archivos cargados no se conservan indefinidamente — confirma poco después de cargar.

### Errores

| Estado | Código              | Condición                                                |
| ------ | ------------------- | -------------------------------------------------------- |
| `403`  | `forbidden`         | El rol del llamante es `viewer`                          |
| `413`  | `file_too_large`    | El archivo subido supera `IMPORT_MAX_FILE_BYTES` (10 MB) |
| `422`  | `validation_failed` | La petición no lleva ninguna parte `file`                |
| `429`  | `too_many_requests` | Se superó el límite de tasa de carga de la organización  |

## Confirmar la importación

`POST /api/v1/projects/{projectId}/imports/commit`

```json
{
  "uploadUlid": "01J...",
  "sourceFormat": "probara_json",
  "targetSuiteUlid": null,
  "replaceMatching": false
}
```

| Campo             | Notas                                                                                                                                                                                                                                                                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uploadUlid`      | El valor devuelto por la llamada de carga anterior.                                                                                                                                                                                                                                                                                                                    |
| `sourceFormat`    | Uno de `probara_json`, `probara_xml`, `probara_csv`, `probara_xlsx`, `qase_xml`, `qase_json`, `qase_csv`, `qase_xlsx`, `testrail_xml`, `testrail_csv`, `gherkin_feature`. El asistente web resuelve este valor automáticamente a partir de la extensión/contenido del archivo subido — un integrador que llama a la API directamente debe establecerlo explícitamente. |
| `targetSuiteUlid` | `null` importa debajo de la raíz del proyecto; en otro caso, la jerarquía de suites del archivo se recrea debajo de la suite indicada.                                                                                                                                                                                                                                 |
| `replaceMatching` | Cuando es `true`, un caso del origen cuyo título coincida exactamente con un caso existente en la suite destino sobrescribe el contenido de ese caso en lugar de crear un duplicado.                                                                                                                                                                                   |

### Respuesta

`200` con el reporte de la confirmación:

```json
{
  "counts": {
    "suitesCreated": 2,
    "casesCreated": 8,
    "casesReplaced": 1,
    "rowsFailed": 0,
    "reviewRequestsCreated": 0
  },
  "created": [{ "caseUlid": "01J...", "displayId": "ACME-42", "title": "Login succeeds" }],
  "replaced": [],
  "reviewRequests": [],
  "failures": [],
  "warnings": []
}
```

`failures` lista las filas que **no** se importaron (el resto del archivo sí se confirmó); `warnings` lista filas que **sí** se importaron pero con un aviso no crítico — ver abajo.

### Proyectos que exigen revisión

Cuando la [revisión de casos de prueba](https://docs.probara.net/es/developers/api/test-case-reviews/) del proyecto es
**obligatoria** (plan Pro o Enterprise), la confirmación no escribe ningún caso. Las suites se crean; cada caso
que la importación crearía se convierte en una solicitud de revisión `create`, y cada caso que
reemplazaría en una solicitud `update`, con quien llama como autor y los revisores por defecto del
proyecto. `casesCreated` y `casesReplaced` valen `0`, `reviewRequestsCreated` cuenta las solicitudes
y `reviewRequests` las lista:

```json
{
  "reviewRequests": [
    {
      "reviewUlid": "01J...",
      "displayId": "RV-7",
      "kind": "update",
      "caseUlid": "01J...",
      "title": "Login succeeds"
    },
    {
      "reviewUlid": "01J...",
      "displayId": "RV-8",
      "kind": "create",
      "caseUlid": null,
      "title": "Signup works"
    }
  ]
}
```

Un caso solo se escribe cuando se fusiona su solicitud, con la misma validación que
`POST .../test-cases` (por ejemplo, los campos personalizados obligatorios deben tener un valor).
Igual que la importación directa, la confirmación no es todo o nada: las solicitudes abiertas antes
de un fallo posterior siguen abiertas.

## Reimportación de Probara: fidelidad completa

Reimportar una exportación de Probara (cualquiera de los cuatro formatos) mapea de vuelta **todos** los campos de clasificación del sistema — prioridad, severidad, estado, tipo, capa, comportamiento, es inestable (flaky), precondiciones y poscondiciones — además de cada valor de campo personalizado definido por el usuario que **ya exista**, emparejado automáticamente por nombre (título para JSON/XML, encabezado de columna convertido a slug para CSV/XLSX). Los pasos, etiquetas, descripción y ruta de suite siempre se conservan íntegramente sin importar la plataforma de origen. También se conservan el formato de pasos del caso y la palabra clave Gherkin de cada paso.

**Nunca se crea un campo ni una opción al importar.** Cada coincidencia se resuelve contra los campos personalizados y las opciones existentes de la organización en el momento de confirmar — no hay carga de mapeo de campos en la petición, ni un paso de vinculación interactivo. Esto hace que la reimportación sea segura de ejecutar repetidamente (por ejemplo, para restaurar un respaldo o migrar casos entre proyectos) sin contaminar el esquema del proyecto.

Los **parámetros** y las **combinaciones excluidas** del caso también hacen el viaje de ida y vuelta. CSV y XLSX los llevan en dos columnas JSON, `parameters` y `excluded_combinations`, después de las columnas de campos personalizados; JSON y XML los llevan como `parameters` y `excludedCombinations`. Las columnas y las claves solo aparecen cuando un caso tiene parámetros o combinaciones excluidas, así que una exportación sin ellos no cambia. Un parámetro compartido vuelve como parámetro local con los valores que tenía. Los nombres `parameters` y `excluded_combinations` están reservados: un campo personalizado con cualquiera de esos títulos no importa sus valores. Un archivo de Probara o `.feature` que no trae parámetros borra los parámetros del caso que reemplaza, mientras que un archivo de Qase o TestRail, que no los trae, los conserva.

Las exportaciones de Qase y TestRail mapean un conjunto más reducido — solo prioridad, tipo y estado. Los campos personalizados definidos por el usuario no se mapean para esas dos plataformas. Un archivo Gherkin `.feature` no mapea campos del sistema ni personalizados; sus etiquetas y suites se importan.

La **clave de automatización** del caso también hace el viaje de ida y vuelta. Un caso reemplazado conserva su clave actual cuando el archivo no trae ninguna, y una clave vacía o solo con espacios la borra. Una clave que la importación no puede aplicar — porque ya la tiene otro caso del proyecto (incluidos los archivados), la repite una fila anterior del mismo archivo o no es válida — nunca hace fallar la fila: el caso se importa sin ella y el informe incluye un aviso `automation_key_skipped`. Las claves se comprueban contra el proyecto tal como estaba antes de la importación, así que una clave que el mismo archivo quita de un caso no puede asignarse a otro en esa importación.

### Comportamiento ante campos y opciones desconocidos

Una importación nunca falla una fila solo porque el valor de un campo no se pudo mapear — en su lugar, confirma el caso y registra un aviso:

| Código de aviso           | Significado                                                                                                                                                                                                                                                                                       |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unmapped_value`          | Un valor de opción del sistema o definido por el usuario no coincidió con ninguna opción existente, y el campo no tiene un valor predeterminado configurado — el campo queda sin asignar.                                                                                                         |
| `defaulted_value`         | Igual que el anterior, pero el campo tiene una opción predeterminada configurada — el campo usa esa opción predeterminada.                                                                                                                                                                        |
| `unmapped_field`          | El título de un campo definido por el usuario (o el slug de una columna CSV/XLSX) no coincidió con ningún campo existente en el proyecto — el valor se omite, no se crea nada.                                                                                                                    |
| `automation_key_skipped`  | La clave de automatización ya la usa otro caso del proyecto, la repite una fila anterior o no es válida — el caso se importa sin ella.                                                                                                                                                            |
| `shared_step_skipped`     | El caso hacía referencia a un paso compartido cuyo texto el archivo no incluye — esa referencia se omite y el caso importa sus demás pasos.                                                                                                                                                       |
| `step_format_folded`      | Los pasos del caso no encajan con su formato indicado: un paso Gherkin sin palabra clave o con resultado esperado, o un paso clásico con palabra clave. El caso se importa como clásico, con cada palabra clave al inicio de su acción.                                                           |
| `parameters_skipped`      | Los parámetros del archivo incumplen una regla de parámetros, como un nombre o una fila repetidos, o más de 100 valores en un parámetro simple — el caso se importa sin ellos. Un reemplazo conserva los parámetros existentes del caso, y los Examples de un archivo `.feature` no se conservan. |
| `image_reference_dropped` | Un paso, una descripción o un valor de párrafo menciona una imagen que no está guardada en esta organización, como en un archivo exportado desde otra organización — esa imagen se quita y el resto del texto se importa.                                                                         |

Cada fila fallida y cada aviso nombra la `sourceRow` y el `title` del caso afectado, de modo que una importación parcialmente exitosa se puede diagnosticar por completo solo con la respuesta.

### Filas fallidas

Una fila falla (y su caso **no** se importa) solo por estas razones — cualquier otro desajuste de valor pertenece a la familia de avisos de arriba, nunca a un fallo:

| Código                    | Condición                                                                                                                                                             |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `missing_title`           | La fila no tiene título.                                                                                                                                              |
| `ambiguous_match`         | `replaceMatching` está activo y el título coincide con más de un caso existente en la suite destino.                                                                  |
| `review_already_open`     | Solo con revisión obligatoria: el caso que la fila reemplazaría ya tiene una solicitud de revisión abierta.                                                           |
| `review_proposal_invalid` | Solo con revisión obligatoria: el contenido de la fila no puede ser una solicitud de revisión (por ejemplo, un título de más de 400 caracteres o un paso sin acción). |

## Archivos Gherkin `.feature`

Carga un archivo `.feature` como de costumbre y luego confírmalo con `sourceFormat` en `gherkin_feature`. El archivo debe contener un único Feature, escrito con palabras clave en inglés. Cada Scenario y cada Scenario Outline se convierte en un caso Gherkin dentro de una suite con el nombre del Feature, y una Rule añade una suite anidada. El Background pasa a ser las precondiciones del caso. Las etiquetas pasan a ser etiquetas de Probara, y las del Feature y las de la Rule se aplican a cada escenario que contienen. Los Examples de un Scenario Outline se convierten en un único parámetro llamado `Examples`: los encabezados de sus tablas forman las columnas, en el orden en que aparecen por primera vez, y se conserva cada fila, en orden, con una celda vacía donde una tabla no tiene esa columna. Una tabla de una sola columna se convierte en un parámetro simple con el nombre de su encabezado. Varios bloques Examples se fusionan en ese parámetro, y sus nombres y etiquetas no se conservan. Cuando los Examples incumplen una regla de parámetros, el caso se importa sin ellos y el informe incluye un aviso `parameters_skipped`. La exportación `.feature` escribe los parámetros de un caso de vuelta como una tabla Examples, con una fila por cada combinación que el caso ejecuta. Una sincronización Gherkin rechaza ese escenario con `422`, porque la sincronización no informa avisos. La descripción del Feature o de la Rule no se importa. Un archivo que el analizador no puede leer falla con `422 parse_failed`, y su mensaje indica la línea. La [guía de casos de prueba Gherkin](https://docs.probara.net/es/guides/gherkin-test-cases/) describe el mismo mapeo para clientes. Los archivos `.feature` de un repositorio pueden mantenerse sincronizados en su lugar con la [sincronización Gherkin](https://docs.probara.net/es/developers/api-reference/#sincronización-de-archivos-gherkin), para que sus casos sigan a los archivos.

## Límites de tamaño

Una importación está acotada a `IMPORT_MAX_CASES` (5000) casos analizados y `IMPORT_MAX_FILE_BYTES` (10 MB) de bytes cargados. Un archivo que supere cualquiera de los dos límites se rechaza antes de escribir cualquier suite o caso.

## Límite de tasa

Tanto la carga como la confirmación están limitadas por organización (10 peticiones/hora cada una). Superar el límite devuelve `429` con `{ "error": { "code": "too_many_requests", ... } }`.

## Markdown no es un formato de importación admitido

Markdown nunca ha sido, ni es, un formato de origen importable. El asistente rechaza un archivo `.md` del lado del cliente con un error en línea traducido; un integrador que carga un archivo `.md` y trata de confirmarlo con cualquier `sourceFormat` recibe `422 parse_failed` — el archivo no se podrá analizar como el formato declarado.

## Errores

| Estado | Código              | Condición                                                                                                                                                                    |
| ------ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `403`  | `forbidden`         | El rol del llamante es `viewer`                                                                                                                                              |
| `404`  | `not_found`         | `projectId`, `targetSuiteUlid`, o el `uploadUlid` cargado no se resuelve en la organización activa                                                                           |
| `413`  | `file_too_large`    | Los bytes cargados superan `IMPORT_MAX_FILE_BYTES` (nueva verificación de refuerzo al confirmar)                                                                             |
| `422`  | `parse_failed`      | Los bytes cargados no se analizaron como el `sourceFormat` declarado, o la jerarquía de suites anida demasiado; para `gherkin_feature`, el mensaje indica la línea que falló |
| `422`  | `empty_import`      | El archivo se analizó y arrojó cero casos                                                                                                                                    |
| `422`  | `too_many_cases`    | La cantidad de casos analizados supera `IMPORT_MAX_CASES`                                                                                                                    |
| `429`  | `too_many_requests` | Se superó el límite de tasa de importación de la organización                                                                                                                |

## Ejemplo

Carga un archivo y luego confírmalo como una reimportación de Probara en JSON:

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -F "file=@acme-export.json" \
  "https://app.probara.net/api/v1/projects/ACME/imports:stage"
```

```bash
curl -sS \
  -H "Authorization: Bearer $PROBARA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uploadUlid":"01J...","sourceFormat":"probara_json","targetSuiteUlid":null,"replaceMatching":false}' \
  "https://app.probara.net/api/v1/projects/ACME/imports/commit"
```

## Páginas relacionadas

- [API de exportación de casos de prueba](https://docs.probara.net/es/developers/api/export/) — produce los archivos que este endpoint reimporta.
