Documentación
Especificación técnica de la API pública de Qably. Describe los endpoints, esquemas de datos y flujos de integración disponibles.
Primeros pasos
Qably centraliza la gestión de calidad para equipos de ingeniería. La plataforma no ejecuta pruebas directamente: los resultados se generan en pipelines externos de integración continua y se envían a Qably vía HTTP. El sistema almacena las ejecuciones y consolida el historial de cambios, suites y cobertura.
Dos flujos independientes
Qably procesa dos flujos de datos desacoplados. Configurar uno no activa el otro, lo cual explica por qué ciertas vistas pueden aparecer vacías inicialmente.
| Pipeline | Endpoint | Credencial | Llena |
|---|---|---|---|
| Resultados de pruebas | POST /runs/ingest | API key del proyecto (Authorization: Bearer) | Suites, casos y ejecuciones en el panel principal |
| Cambios de código | POST /webhooks/scm/:provider | Firma HMAC (sin API key) | Historial de commits, lotes de ingesta y trazabilidad en la vista Repository |
Requisitos previos
- Una cuenta en Qably con al menos una organización activa.
- Un repositorio alojado en GitHub o Bitbucket (proveedores compatibles actualmente).
- Un pipeline de CI con capacidad de ejecutar pruebas y enviar peticiones HTTP al concluir.
1. Crear el proyecto
Cada proyecto está vinculado a una organización. Para crearlo, diríjase a Proyectos > Nuevo proyecto en la consola web.
- Nombre (obligatorio, hasta 80 caracteres)
- Descripción (opcional, hasta 500 caracteres)
- Tecnologías (opcional, se autocompletan al vincular el repositorio en el siguiente paso)
No es indispensable contar con un repositorio vinculado para inicializar el proyecto. Conectar el repositorio, generar la API key y configurar el reporte en CI son pasos independientes que pueden realizarse en cualquier orden.
2. Conectar el repositorio mediante el webhook del SCM
Este paso habilita el flujo de cambios de código. Qably recibe las actualizaciones mediante webhooks enviados por el proveedor del repositorio, de forma independiente a la API key del paso 3.
Selección del repositorio
- Inicie sesión con GitHub o Bitbucket si aún no lo ha hecho. Qably utiliza este token de OAuth para listar los repositorios accesibles en su cuenta personal y organizaciones asociadas.
- En la sección Integraciones del proyecto, seleccione el repositorio deseado de la lista disponible, ordenada por fecha de push reciente.
- Al seleccionar un repositorio no vinculado, se crea una conexión dentro de la organización y se genera su secreto de webhook. Seleccionar un repositorio previamente vinculado reutiliza la conexión existente.
Registro del webhook en el proveedor
Qably no registra webhooks de forma automática en proveedores externos. Debe agregarse manualmente en la configuración del repositorio.
- Obtenga el secreto ejecutando POST /connections/:id/webhook-secret desde la interfaz de la conexión. La respuesta entrega el valor en texto plano una sola vez (al crearlo o rotarlo), por lo que debe copiarse inmediatamente.
- En GitHub, acceda a Settings > Webhooks > Add webhook dentro del repositorio.
- Payload URL: https://api.qably.dev/webhooks/scm/github
- Content type: application/json
- Secret: el valor obtenido en el paso anterior
- Events: seleccione push como mínimo. Se recomienda marcar también pull request para registrar la actividad completa del equipo.
Las conexiones de Bitbucket siguen el mismo principio, utilizando el encabezado de firma propio de Bitbucket. Actualmente, GitHub y Bitbucket son los dos proveedores compatibles.
3. Emitir una API key
Este paso habilita el flujo de resultados de pruebas, proporcionando una credencial de máquina para que el pipeline de CI reporte ejecuciones sin requerir una sesión de usuario.
- En la pestaña API Keys del proyecto, cree una clave asignándole un nombre identificable como "CI/CD Pipeline". Esta acción requiere rol de owner o admin en la organización.
- El token generado sigue la estructura qbly_<lookupId>_<secret> y se muestra una única vez en la pantalla de confirmación. Qably almacena únicamente su hash SHA-256 y no puede recuperarlo posteriormente.
- Guarde el valor en su proveedor de CI. En GitHub Actions, vaya a Settings > Secrets and variables > Actions > Secrets y cree el secreto de repositorio QABLY_API_KEY. Si utiliza una URL personalizada, agregue la variable QABLY_API_BASE_URL en la pestaña Variables. Nunca incluya este token en el repositorio de código.
Cada API key tiene alcance exclusivo sobre un proyecto y únicamente permite registrar ejecuciones. No tiene permisos de lectura sobre otros proyectos ni facultades administrativas sobre la organización. El proyecto destino se infiere directamente de la clave.
Revocar una clave desactiva su uso de forma inmediata pero conserva los registros históricos asociados. Es posible mantener múltiples claves activas simultáneamente para facilitar la rotación sin interrumpir los pipelines de CI.
4. Reportar resultados desde CI
Para conectar Qably a su integración continua, cree un archivo de flujo de trabajo en su repositorio (por ejemplo, .github/workflows/ci.yml). El lenguaje YAML organiza el pipeline a través de los eventos de activación on, la definición de entornos bajo jobs y la secuencia ordenada de comandos en steps para preparar el entorno, ejecutar las pruebas y enviar el reporte.
En Jest, instale jest-junit y defina JEST_JUNIT_ADD_FILE_ATTRIBUTE como "true" para que el XML incluya la ruta de archivo de cada caso de prueba, lo que permite a Qably vincular las pruebas con el código fuente. En Vitest, el reporte JUnit se genera de forma nativa indicando el reporter correspondiente en la línea de comandos.
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
name: Run tests and report to Qably
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Run Jest tests
env:
JEST_JUNIT_OUTPUT_DIR: ./reports
JEST_JUNIT_OUTPUT_NAME: junit.xml
JEST_JUNIT_ADD_FILE_ATTRIBUTE: 'true'
run: npx jest --ci --reporters=default --reporters=jest-junit
- name: Report results to Qably
if: always()
env:
QABLY_API_KEY: ${{ secrets.QABLY_API_KEY }}
run: |
curl --fail --silent --request POST \
"https://api.qably.dev/runs/ingest/junit?externalId=gha-${{ github.run_id }}-${{ github.job }}&source=github_actions" \
--header "Authorization: Bearer $QABLY_API_KEY" \
--header "Content-Type: application/xml" \
--data-binary @./reports/junit.xml || true
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
name: Run tests and report to Qably
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Run Vitest tests
run: npx vitest run --reporter=default --reporter=junit --outputFile=./reports/junit.xml
- name: Report results to Qably
if: always()
env:
QABLY_API_KEY: ${{ secrets.QABLY_API_KEY }}
run: |
curl --fail --silent --request POST \
"https://api.qably.dev/runs/ingest/junit?externalId=gha-${{ github.run_id }}-${{ github.job }}&source=github_actions" \
--header "Authorization: Bearer $QABLY_API_KEY" \
--header "Content-Type: application/xml" \
--data-binary @./reports/junit.xml || true
El endpoint POST /runs/ingest/junit recibe el archivo XML directo y procesa todo en el servidor. Si el reporte contiene suites o casos no registrados previamente, Qably los crea de forma automática en ese proyecto.
5. Verificar que llegaron los datos
Cada flujo se valida de forma independiente, dado que uno puede estar recibiendo datos mientras el otro requiere ajustes de configuración.
- Resultados de pruebas: abra el proyecto y verifique la ejecución recién enviada por CI. El estado general del run se deriva de sus casos: cualquier prueba fallida marca el run como fallido; casos en ejecución o pendientes lo mantienen en progreso; y se considera exitoso cuando al menos un caso pasa o se omite sin fallas acompañantes.
- Cambios de código: requiere haber completado el paso 2. La vista Repository del proyecto debe reflejar el lote de ingesta correspondiente al push o pull request más reciente.
Reportar JUnit XML desde cualquier lenguaje
El backend de Qably procesa cualquier archivo con estructura estándar <testsuite>/<testcase>, extrayendo el resultado de cada prueba a partir de los elementos <failure>, <error> o <skipped>. Genere el reporte XML utilizando las herramientas nativas de su lenguaje y envíe el archivo resultante en su pipeline de CI.
JavaScript y TypeScript
Jest y Vitest se detallaron en el paso anterior y mantienen la misma configuración.
PLAYWRIGHT_JUNIT_OUTPUT_NAME=results.xml npx playwright test --reporter=junit
pytest --junitxml=report.xml
mvn test
# genera target/surefire-reports/TEST-*.xml
./gradlew test
# genera build/test-results/test/TEST-*.xml
phpunit --log-junit junit.xml
phpunit -c phpunit.xml
dotnet test --logger:"junit;LogFilePath=test-result.xml"
go test -v ./... 2>&1 | go-junit-report > report.xml
El reporter de JUnit incorporado en Playwright escribe a la salida estándar a menos que se indique un archivo, ya sea mediante una variable de entorno o en el archivo de configuración.
También puede configurarse una vez en playwright.config.ts: reporter: [['junit', { outputFile: 'results.xml' }]].
mvn test escribe un reporte por clase de prueba sin ninguna bandera extra; el plugin Surefire lo hace por defecto.
PHPUnit 9 y anteriores aceptan una bandera directa por línea de comandos. PHPUnit 10 en adelante la eliminó, por lo que el archivo de salida se configura en phpunit.xml.
El paquete NuGet JunitXml.TestLogger se agrega como dependencia, y el logger se pasa por línea de comandos.
Cómo nombrar tus pruebas para Qably
Qably deriva los nombres de las pruebas y suites a partir de los identificadores emitidos por el ejecutor de pruebas y la estructura de archivos del repositorio. Los títulos definidos en el código se reflejan directamente en la plataforma, convirtiendo los nombres de las pruebas en documentación técnica accesible para todo el equipo.
Las siguientes pautas de diseño ayudan a estructurar suites descriptivas y legibles:
- Agrupe por funcionalidad de negocio en lugar de estructuras técnicas o clases internas. Los bloques descriptivos deben reflejar la acción del usuario (por ejemplo, "Carrito de compras" en lugar de "CartServiceImpl").
- Redacte cada prueba combinando un verbo en presente y la condición esperada: "rechaza un token vacío", "acepta un token de hasta 500 caracteres".
- Limite cada prueba a un comportamiento específico. Nombres que requieren conectores como "y" suelen indicar casos compuestos que conviene independizar.
- Nombre el archivo según el módulo o funcionalidad que valida, ya que este nombre define el título de la suite en Qably.
Normalización automática de nombres
Durante la ingesta, Qably formatea identificadores técnicos en texto legible separando palabras en camelCase o snake_case y omitiendo prefijos comunes como "test", "spec", "prueba" o "caso". De este modo, un identificador como testTokenNull se registra en la plataforma como "Token null".
Si el nombre en el código ya está formulado como una oración (por ejemplo, "debe rechazar un token vacío"), Qably conserva la redacción intacta capitalizando únicamente la primera letra sin alterar el verbo ni recortar términos.
Un ejemplo antes y después
| En lugar de | Escribe |
|---|---|
| test_login_1 | inicia sesión con credenciales válidas |
| testTokenNull | rechaza un token vacío |
| should return 400 when body is invalid and user is anonymous | rechaza una solicitud con cuerpo inválido |
| UserServiceTest.java | registro-de-usuarios |
No es necesario renombrar pruebas existentes para comenzar a utilizar Qably. La plataforma importa los identificadores actuales y respeta cualquier ajuste manual posterior: si un miembro del equipo edita el título de un caso desde la consola, las importaciones subsecuentes preservan el valor modificado.
Referencia: POST /runs/ingest
Registra los resultados de ejecución de una suite de pruebas. Requiere autenticación mediante el encabezado Authorization: Bearer <API key del proyecto>. El proyecto y la organización se determinan a partir de la clave.
curl --fail --silent \
--request POST \
"https://api.qably.dev/runs/ingest" \
--header "Authorization: Bearer $QABLY_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"externalId": "gh-run-482913",
"source": "github_actions",
"suiteId": "suite_123",
"name": "Checkout regression - main",
"startedAt": "2026-09-01T10:00:00Z",
"finishedAt": "2026-09-01T10:04:12Z",
"commitSha": "a1b2c3d",
"commitMessage": "fix: checkout rounding",
"commitAuthor": "Ada Lovelace",
"cases": [
{ "name": "Adds an item to the cart", "status": "pass" },
{
"name": "Applies a discount code",
"steps": ["open cart", "apply code SAVE10"],
"expectedResult": "total is reduced by 10%",
"status": "fail"
}
]
}'
const response = await fetch('https://api.qably.dev/runs/ingest', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.QABLY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
externalId: 'gh-run-482913',
source: 'github_actions',
suiteId: 'suite_123',
name: 'Checkout regression - main',
startedAt: '2026-09-01T10:00:00Z',
finishedAt: '2026-09-01T10:04:12Z',
commitSha: 'a1b2c3d',
commitMessage: 'fix: checkout rounding',
commitAuthor: 'Ada Lovelace',
cases: [
{ name: 'Adds an item to the cart', status: 'pass' },
{
name: 'Applies a discount code',
steps: ['open cart', 'apply code SAVE10'],
expectedResult: 'total is reduced by 10%',
status: 'fail',
},
],
}),
});
import os
import requests
response = requests.post(
"https://api.qably.dev/runs/ingest",
headers={"Authorization": f"Bearer {os.environ['QABLY_API_KEY']}"},
json={
"externalId": "gh-run-482913",
"source": "github_actions",
"suiteId": "suite_123",
"name": "Checkout regression - main",
"startedAt": "2026-09-01T10:00:00Z",
"finishedAt": "2026-09-01T10:04:12Z",
"commitSha": "a1b2c3d",
"commitMessage": "fix: checkout rounding",
"commitAuthor": "Ada Lovelace",
"cases": [
{"name": "Adds an item to the cart", "status": "pass"},
{
"name": "Applies a discount code",
"steps": ["open cart", "apply code SAVE10"],
"expectedResult": "total is reduced by 10%",
"status": "fail",
},
],
},
)
response.raise_for_status()
| Campo | Obligatorio | Notas |
|---|---|---|
| externalId | sí | Cadena no vacía. Clave de idempotencia para actualizar ejecuciones existentes en lugar de duplicarlas. |
| source | no | "api" (valor por defecto) o "github_actions". |
| suiteId / suiteName | exactamente uno | Un suiteId inexistente devuelve 404. Un suiteName inexistente crea la suite automáticamente. |
| name | sí | Nombre descriptivo de la ejecución, hasta 200 caracteres. |
| startedAt / finishedAt | no | Marcas temporales ISO 8601 con zona horaria explícita. |
| commitSha / commitMessage / commitAuthor | no | Metadatos opcionales del commit, hasta 64, 2000 y 200 caracteres respectivamente. |
| cases | sí | Arreglo con al menos un caso de prueba. |
| Campo del caso | Obligatorio | Notas |
|---|---|---|
| name | sí | Hasta 120 caracteres. |
| suiteName | no | Hereda el nombre de la suite resuelta; permite conservar etiquetas adicionales (como proyectos de Playwright) para trazabilidad. |
| steps | no | Arreglo de texto de hasta 50 elementos (máximo 500 caracteres por elemento). JUnit XML no incluye este campo, por lo que llega vacío por defecto salvo cuando se envía JSON directamente. |
| expectedResult | no | Hasta 1000 caracteres. Llega vacío por defecto al importar desde JUnit XML. |
| status | sí | Valores permitidos: pending, running, pass, fail, skip, blocked. |
| recordedAt | no | Marca temporal ISO 8601 con zona horaria explícita. |
El estado general de la ejecución se evalúa en el servidor y no depende de valores calculados por el cliente. Si un caso de prueba falla, la ejecución se marca como fallida. Si existen casos pendientes o en progreso sin fallos, la ejecución permanece en estado de ejecución. La ejecución finaliza como exitosa cuando al menos un caso concluye en pass o skip. Una ejecución donde todos los casos están bloqueados se califica como fallida, ya que ninguna validación fue completada.
Reutilizar la combinación de proyecto, origen y externalId actualiza los datos existentes sin crear duplicados: la lista de casos se reemplaza íntegramente y los metadatos opcionales se actualizan si se incluyen en la nueva petición. El endpoint responde 200 OK tanto en la creación inicial como en actualizaciones.
Referencia: POST /runs/ingest/junit
Permite enviar archivos JUnit XML en formato original para su análisis en el servidor. Utiliza las mismas credenciales de autenticación que POST /runs/ingest.
El cuerpo de la petición contiene el archivo XML directo con cabecera Content-Type en application/xml o text/xml (hasta 10 MB). Los parámetros de configuración se transmiten mediante la cadena de consulta (query string).
| Parámetro de consulta | Obligatorio | Notas |
|---|---|---|
| externalId | sí | Clave de idempotencia idéntica a POST /runs/ingest. |
| source | no | "api" (valor por defecto) o "github_actions". |
| suiteId / suiteName | no | Mismas reglas de resolución que en JSON. Si se omiten ambos, el nombre de la suite se toma del atributo name en <testsuite>. |
| name | no | Si se omite, adopta el nombre de la suite del reporte. |
| startedAt / finishedAt / commitSha / commitMessage / commitAuthor | no | Campos equivalentes a POST /runs/ingest. |
curl --fail --silent \
--request POST \
"https://api.qably.dev/runs/ingest/junit?externalId=ci-42" \
--header "Authorization: Bearer $QABLY_API_KEY" \
--header "Content-Type: application/xml" \
--data-binary @junit.xmlEl título de cada caso se extrae del atributo name en <testcase>. El atributo classname solo se utiliza como valor de respaldo si name está ausente. Los archivos con sintaxis XML inválida o cuerpos vacíos reciben una respuesta HTTP 400.
Referencia: POST /webhooks/scm/:provider
El parámetro :provider acepta los valores github o bitbucket (indistinto de mayúsculas). Este endpoint no utiliza API keys: cada entrega se valida mediante el secreto HMAC configurado para la conexión del repositorio.
| GitHub | Bitbucket | |
|---|---|---|
| Encabezado de firma | x-hub-signature-256 (formato sha256=<hex>) | x-hub-signature (formato sha256=<hex>) |
| Encabezado de evento | x-github-event: push o pull_request | x-event-key: repo:push, pullrequest:created o pullrequest:updated |
| Encabezado de id de entrega | x-github-delivery | x-request-uuid |
| Acciones de pull request manejadas | opened, synchronize | created, updated |
| Respuesta | Significado |
|---|---|
| 202, { "status": "accepted" } | Firma válida. Evento almacenado y encolado para su procesamiento. |
| 202, { "status": "duplicate" } | El par (proveedor, id de entrega) ya fue procesado. Las entregas repetidas son idempotentes. |
| 202, { "status": "ignored" } | Firma válida pero tipo de evento no soportado por Qably. |
| 404 | Proveedor no reconocido en la ruta. |
| 401 | Fallo de verificación de firma contra las conexiones del repositorio. |
| 400 | Cuerpo de la petición inválido o JSON mal formado. |
Límite de tasa de 60 peticiones por minuto por instancia. Los eventos aceptados se procesan en segundo plano de manera asíncrona. La respuesta HTTP confirma la recepción correcta del evento, no la conclusión de su procesamiento.
Rotación del secreto
Cada conexión almacena su propio secreto HMAC. Si el secreto en el proveedor difiere del registrado en Qably, las entregas responderán con código 401. Al solicitar la rotación, Qably genera un nuevo valor, lo almacena cifrado y lo retorna en la respuesta por única vez.
| Acción | Endpoint | Rol requerido |
|---|---|---|
| Rotar el secreto del webhook | POST /projects/:projectId/repository/webhook-secret | owner o admin |
La respuesta HTTP 201 entrega el objeto { "webhookSecret": "<64 caracteres hexadecimales>" }. Este valor debe copiarse inmediatamente en la configuración del webhook en el repositorio. El secreto anterior queda invalidado al instante. Solicitar la rotación en un proyecto sin repositorio vinculado responde con código 404.
Referencia: API keys
Las claves siguen la estructura qbly_<lookupId>_<secret>. Incorporan un prefijo constante, un identificador público de 6 bytes para ubicar el registro y un secreto criptográfico de 32 bytes para la autenticación. Qably almacena únicamente el hash SHA-256 y realiza comprobaciones en tiempo constante. El token en texto plano no puede recuperarse tras su emisión.
| Acción | Endpoint | Rol requerido |
|---|---|---|
| Listar keys | GET /projects/:projectId/api-keys | Cualquier miembro de la organización |
| Crear una key | POST /projects/:projectId/api-keys (cuerpo: { "name": string }) | owner o admin |
| Revocar una key | POST /projects/:projectId/api-keys/:id/revoke | owner o admin |
Las claves revocadas permanecen archivadas en el sistema para conservar la trazabilidad de las ejecuciones históricas. Se envían en el encabezado Authorization: Bearer qbly_<lookupId>_<secret>.
Referencia: variables de entorno
Variables requeridas en los entornos de CI para la integración con Qably:
| Variable | Obligatoria | Notas |
|---|---|---|
| QABLY_API_KEY | sí (para reportar datos) | Clave de autenticación del proyecto en CI. Si no está configurada, las peticiones sin autenticar se rechazan con código 401. |
| QABLY_API_BASE_URL | no | Por defecto apunta a https://api.qably.dev. Puede configurarse para instancias privadas o pruebas locales contra http://localhost:3001. |
Notificar por Discord o Slack
Qably puede enviar alertas a canales de Discord o espacios de trabajo de Slack ante eventos de ejecuciones fallidas o exitosas, regresiones de casos, fallos de ingesta y cambios en credenciales de conexión. Los webhooks se gestionan en las plataformas de destino; Qably únicamente despacha las notificaciones hacia la URL configurada.
Obtener una URL de webhook de Discord
- En el servidor de Discord donde desea recibir alertas, abra Configuración del servidor > Integraciones > Webhooks.
- Seleccione Nuevo Webhook, asigne el canal deseado y copie la URL generada.
Obtener una URL de webhook de Slack
- Cree o configure una aplicación en api.slack.com/apps y active la función Incoming Webhooks.
- Instale la app en su espacio de trabajo, seleccione el canal y copie la URL asignada por Slack.
Conectarlo a Qably
- En Configuración > Integraciones, dentro de Canales de notificación del equipo, seleccione Agregar canal.
- Seleccione Discord o Slack, asigne un nombre al canal, pegue la URL del webhook y marque los eventos correspondientes.
- Utilice la opción de envío de prueba para verificar la recepción del mensaje antes de activar el canal.
| Evento | Se dispara cuando |
|---|---|
| Ejecución fallida | La ejecución concluye con al menos una prueba fallida. |
| Ejecución completada | La ejecución concluye con todas las pruebas aprobadas. |
| Caso con regresión | Una prueba que previamente pasaba falla en la ejecución actual. |
| Ingesta fallida | Ocurre un error al procesar los cambios de código del repositorio. |
| Seguridad de la conexión | Se modifica el secreto del webhook o las credenciales vinculadas al repositorio. |
Preguntas frecuentes
- ¿Por qué mi pipeline de CI finaliza con éxito pero no aparece la ejecución en Qably?
Verifique que la variable QABLY_API_KEY esté declarada como secreto en el entorno del job de CI y que el paso de reporte se haya ejecutado. Al incluir la directiva if: always(), el envío se realiza incluso si las pruebas fallaron.
Confirme además que su ejecutor de pruebas generó el archivo XML en la ruta indicada antes de la petición. Si la llamada con curl devuelve un código HTTP de error (como 401 por una clave revocada o 400 por un archivo XML mal formado), revise los registros del runner para confirmar el motivo exacto.
- ¿Cómo organiza Qably las suites y casos de prueba si no especifico identificadores manuales?
Al importar un reporte JUnit XML, Qably lee los atributos del archivo para identificar cada suite y cada caso. Si una suite con ese nombre no existe en el proyecto, el servidor la crea de inmediato y le asigna los casos correspondientes.
No es necesario registrar previamente las pruebas en la interfaz web ni gestionar identificadores numéricos. Si envía datos mediante la API JSON en lugar de XML, use el campo suiteName para que el sistema adopte o cree la suite de forma automática.
- ¿Qué sucede en Qably si reintento un job de pruebas en mi CI?
Qably maneja reintentos de forma idempotente cuando se incluye el parámetro externalId en la llamada. Al utilizar identificadores únicos provistos por el runner (como el número de ejecución y el nombre del job en GitHub Actions), el servidor actualiza el registro existente en lugar de crear una ejecución duplicada.
Esto garantiza que las métricas de aprobación reflejen el estado definitivo de la corrida sin distorsionar el historial del proyecto ni duplicar conteos de pruebas.
- ¿Puedo registrar pasos individuales y resultados esperados al importar desde JUnit XML?
El estándar JUnit XML registra únicamente el estado final de cada prueba (aprobada, fallida u omitida), su duración y el mensaje de error o traza del fallo. Por esta razón, las importaciones desde archivos XML dejan vacíos los campos de pasos y resultados esperados.
Para documentar procedimientos detallados con pasos individuales y resultados previstos, envíe los datos en formato JSON directamente al endpoint POST /runs/ingest, o gestione casos estructurados desde la interfaz web del proyecto.
- ¿Por qué la sección Repository del proyecto no muestra commits ni ramas?
La vista Repository se alimenta exclusivamente mediante el webhook del sistema de control de versiones (GitHub o Bitbucket). El envío de reportes de pruebas desde CI registra ejecuciones en el historial, pero no transmite el contenido de los commits ni la actividad del repositorio.
Para ver los cambios de código y vincularlos con las corridas de pruebas, configure el webhook en los ajustes de su repositorio siguiendo el paso 2 de esta guía.
- ¿Puede una misma API key reportar resultados a varios proyectos?
No. Cada API key tiene alcance exclusivo sobre un proyecto específico dentro de la organización. El servidor deduce el proyecto de destino a partir de la propia clave y restringe su uso a la ingesta de pruebas.
Para entornos con múltiples proyectos o arquitecturas basadas en microservicios, genere una clave independiente para cada proyecto y configure el secreto correspondiente en sus flujos de CI.