Docs de Autonomy
Integraciones

GitHub Actions

Inicia ejecuciones de Autonomy desde un workflow de GitHub Actions para una previsualización web o un APK de Android, y haz fallar el workflow salvo que todas las ejecuciones se superen.

Usa GitHub Actions cuando quieras Autonomy como un paso de tu propio workflow: después de un script de despliegue propio, para un build móvil o antes de un job de release. El workflow inicia las ejecuciones, espera sus resultados y falla salvo que todas las ejecuciones sean Passed.

Para ejecutar un plan de pruebas en cada pull request sin archivo de workflow, usa la GitHub App. Ejecuta el plan de pull requests del proyecto contra el despliegue de previsualización e informa con un check de GitHub. Consulta Pruebas de pull requests.

Dónde va en el workflow

Pon el paso de Autonomy después del job que despliega la previsualización o compila la app. La ejecución debe recibir la URL definitiva que abriría quien revisa, o el propio archivo del build. El ejemplo web de abajo toma una URL ya desplegada; no despliega tu app.

Cada workflow de abajo es un archivo completo. Si lo añades a un workflow existente, conserva tus jobs de build y de despliegue y apunta needs al job que produce la URL o el build.

Secretos necesarios

En Settings → Secrets and variables → Actions del repositorio, añade:

NombreTipoValor
AUTONOMY_API_KEYSecretUna clave de API de la organización que empieza por aut_. Los propietarios y administradores crean claves en Organization → API keys.
AUTONOMY_TEST_PLAN_IDVariableEl plan de pruebas que ejecutar. Ábrelo en Test plans del proyecto: el ID es la última parte de la URL de la página, /p/<project>/plans/<id>.
PREVIEW_URLVariableSolo web: una URL HTTPS desplegada a la que Autonomy pueda llegar desde internet, no localhost.
AUTONOMY_IOS_BUNDLE_IDVariableSolo iOS: el bundle ID de la app compilada.
AUTONOMY_ANDROID_PACKAGE_NAMEVariableSolo Android: el application ID del APK compilado.

Valores opcionales que lee el script:

  • AUTONOMY_TEST_CASE_ID: ejecuta un caso de prueba en lugar de un plan. Su ID es la última parte de /p/<project>/tests/<id>. Define exactamente uno de AUTONOMY_TEST_CASE_ID y AUTONOMY_TEST_PLAN_ID.
  • AUTONOMY_ENVIRONMENT_SLUG: ejecuta contra un entorno guardado del mismo proyecto, con sus objetivos y valores del entorno, en lugar de la URL o el build de este job. En ese caso el script omite la subida.
  • AUTONOMY_WAIT_SECONDS: el tiempo de espera total para todas las ejecuciones, 1.200 segundos por defecto.

Sin un entorno, una ejecución no tiene valores del entorno: un paso que usa {{env.NAME}} termina como Couldn't start. Define AUTONOMY_ENVIRONMENT_SLUG o usa casos de prueba que no necesiten valores del entorno. Usa un plan de pruebas distinto para cada plataforma, para que cada resultado apunte a la app correcta.

URL de previsualización web

Crea una carpeta .ci en la raíz del repositorio y guarda este script como .ci/autonomy.sh. Todos los workflows de esta página, y las recetas de GitLab, Jenkins, Bitrise y CircleCI, usan este mismo archivo. Necesita Bash, jq y curl 7.76 o posterior; los runners alojados de GitHub los incluyen.

.ci/autonomy.sh
#!/usr/bin/env bash
# Usage: bash .ci/autonomy.sh web|ios|android
# Starts Autonomy runs for this CI job and exits 0 only if every run passed.
set -euo pipefail
set +x
: "${AUTONOMY_API_KEY:?Set an aut_ organization API key}"
: "${AUTONOMY_REQUEST_ID:?Set an ID that is unique for this CI job attempt}"
platform="${1:?Usage: bash .ci/autonomy.sh web|ios|android}"
api="${AUTONOMY_API_URL:-https://api.autonomyqa.com}"
api="${api%/}"

post() {
  curl --fail-with-body --silent --show-error \
    --connect-timeout 15 --max-time 90 \
    -X POST "$api$1" \
    -H "Authorization: Bearer $AUTONOMY_API_KEY" \
    -H 'Content-Type: application/json' --data-binary "$2"
}

# 1. What to run: a test plan or one test case.
if [ -n "${AUTONOMY_TEST_PLAN_ID:-}" ] && [ -z "${AUTONOMY_TEST_CASE_ID:-}" ]; then
  what=$(jq -n --arg id "$AUTONOMY_TEST_PLAN_ID" '{testPlanId:$id}')
elif [ -n "${AUTONOMY_TEST_CASE_ID:-}" ] && [ -z "${AUTONOMY_TEST_PLAN_ID:-}" ]; then
  what=$(jq -n --arg id "$AUTONOMY_TEST_CASE_ID" '{testCaseId:$id}')
else
  echo 'Set exactly one of AUTONOMY_TEST_PLAN_ID or AUTONOMY_TEST_CASE_ID.' >&2
  exit 2
fi

# 2. Where to run: a saved environment, or this job's preview URL or build.
if [ -n "${AUTONOMY_ENVIRONMENT_SLUG:-}" ]; then
  where=$(jq -n --arg slug "$AUTONOMY_ENVIRONMENT_SLUG" '{environmentSlug:$slug}')
else
  case "$platform" in
    web)
      : "${PREVIEW_URL:?Set PREVIEW_URL, or AUTONOMY_ENVIRONMENT_SLUG}"
      where=$(jq -n --arg url "$PREVIEW_URL" '{targets:{web:{baseUrl:$url}}}')
      ;;
    ios|android)
      : "${ARTIFACT_PATH:?Set the path to the zipped .app, .apk or .aab}"
      : "${APP_IDENTIFIER:?Set the iOS bundle ID or Android package name}"
      file=$(basename "$ARTIFACT_PATH")
      bytes=$(wc -c < "$ARTIFACT_PATH" | tr -d '[:space:]')
      if [ "$platform" = ios ]; then
        type=application/zip
      else
        type=application/vnd.android.package-archive
      fi
      upload=$(post /api/artifacts/upload-url "$(jq -n \
        --arg platform "$platform" --arg fileName "$file" \
        --arg contentType "$type" --argjson declaredBytes "$bytes" \
        '{platform:$platform,fileName:$fileName,contentType:$contentType,declaredBytes:$declaredBytes}')")
      storage=$(jq -er '.storageId' <<< "$upload")
      intent=$(jq -er '.intentId' <<< "$upload")
      curl --fail-with-body --silent --show-error \
        --connect-timeout 15 --max-time 600 \
        -X PUT "$(jq -er '.uploadUrl' <<< "$upload")" \
        -H "Content-Type: $type" --data-binary "@$ARTIFACT_PATH"
      scan=$(post /api/artifacts/scan "$(jq -n \
        --arg storageId "$storage" --arg intentId "$intent" \
        '{storageId:$storageId,intentId:$intentId}')")
      if [ "$(jq -r '.status' <<< "$scan")" != clean ]; then
        echo 'The build did not pass the safety check, so no run was started:' >&2
        jq -r '.findings[]?.message' <<< "$scan" >&2
        exit 1
      fi
      where=$(jq -n --arg p "$platform" --arg storageId "$storage" \
        --arg fileName "$file" --arg id "$APP_IDENTIFIER" \
        '{targets:{($p):({storageId:$storageId,sourceMode:"upload",fileName:$fileName}
          + (if $p == "ios" then {bundleId:$id} else {packageName:$id} end))}}')
      ;;
    *) echo 'Usage: bash .ci/autonomy.sh web|ios|android' >&2; exit 2 ;;
  esac
fi

# 3. Start the runs. A plan starts one run per test case.
#    The request ID's prefix (github, gitlab, ...) names the CI provider.
body=$(jq -n --argjson what "$what" --argjson where "$where" \
  --arg platform "$platform" \
  --arg branch "${AUTONOMY_BRANCH:-}" --arg pr "${AUTONOMY_PR:-}" \
  --arg commitSha "${AUTONOMY_COMMIT_SHA:-}" \
  --arg provider "${AUTONOMY_REQUEST_ID%%:*}" \
  --arg key "$AUTONOMY_REQUEST_ID:$platform" \
  '$what + $where + ({
     platforms: [$platform],
     branch: $branch,
     pr: $pr,
     deployment: ({provider: $provider, branch: $branch, commitSha: $commitSha}
       | with_entries(select(.value != ""))),
     idempotencyKey: $key
   } | with_entries(select(.value != "")))')
run_ids=$(post /api/v1/run.trigger "$body" | jq -er '.runIds[]')
printf 'Started Autonomy runs:\n%s\n' "$run_ids"

# 4. Follow each run until it ends. run.get waits up to 25 s for a change;
#    sending the last cursor back makes each call wait for something new.
deadline=$((SECONDS + ${AUTONOMY_WAIT_SECONDS:-1200}))
all_passed=true
for run_id in $run_ids; do
  cursor=null
  while :; do
    left=$((deadline - SECONDS))
    if [ "$left" -le 0 ]; then
      echo "Stopped waiting for run $run_id after AUTONOMY_WAIT_SECONDS. It keeps going in Autonomy." >&2
      exit 1
    fi
    wait_ms=$(( left < 25 ? left * 1000 : 25000 ))
    run=$(post /api/v1/run.get "$(jq -n --arg runId "$run_id" \
      --argjson cursor "$cursor" --argjson waitMs "$wait_ms" \
      '{runId:$runId,cursor:$cursor,waitMs:$waitMs}')")
    cursor=$(jq '.cursor' <<< "$run")
    status=$(jq -r '.status' <<< "$run")
    [ "$status" = queued ] || [ "$status" = running ] || break
  done

  name="$(jq -r '.testCaseName' <<< "$run") ($run_id)"
  case "$status" in
    passed)
      echo "Passed: $name" ;;
    failed)
      echo "Failed: $name. Open the run in Autonomy to see which step failed." >&2
      all_passed=false ;;
    couldnt_start)
      echo "Couldn't start: $name. The environment couldn't be tested, so this says nothing about your app. Open the run for the reason, fix it and run again." >&2
      all_passed=false ;;
    cancelled)
      echo "Cancelled: $name." >&2
      all_passed=false ;;
    *)
      echo "Unexpected status $status: $name." >&2
      all_passed=false ;;
  esac
done

if [ "$all_passed" != true ]; then
  echo 'Not every Autonomy run passed.' >&2
  exit 1
fi
echo 'Every Autonomy run passed.'

Guarda esto como .github/workflows/autonomy-web.yml. Lánzalo desde Actions → Autonomy web → Run workflow, opcionalmente con una URL de previsualización.

.github/workflows/autonomy-web.yml
name: Autonomy web

on:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      preview_url:
        description: Preview URL to test
        required: false

jobs:
  autonomy:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v5
      - name: Run Autonomy
        env:
          AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
          AUTONOMY_TEST_PLAN_ID: ${{ vars.AUTONOMY_TEST_PLAN_ID }}
          PREVIEW_URL: ${{ inputs.preview_url || vars.PREVIEW_URL }}
          AUTONOMY_REQUEST_ID: github-actions:${{ github.run_id }}:${{ github.run_attempt }}
          AUTONOMY_BRANCH: ${{ github.head_ref || github.ref_name }}
          AUTONOMY_COMMIT_SHA: ${{ github.sha }}
        run: bash .ci/autonomy.sh web

Si un job anterior despliega la previsualización, expón su URL como output del job, añade ese job a needs y define PREVIEW_URL: ${{ needs.deploy.outputs.url }}.

Entrega de builds móviles

Usa el mismo .ci/autonomy.sh. Para iOS y Android pide una URL de subida, sube el build, espera a que el control de seguridad salga limpio y después inicia las ejecuciones con el build subido.

iOS

Las pruebas en iOS llegarán pronto. Guarda esto para cuando estén disponibles. Hasta entonces, Autonomy no inicia ejecuciones en iOS.

Compila el .app de simulador en macOS, comprímelo allí en zip para que se conserven los permisos y los enlaces simbólicos, y pasa el zip a un job de Linux como artifact de Actions. Así la subida y la espera consumen minutos de Linux. Sustituye MyApp y la ruta del workspace por los tuyos; en un proyecto sin workspace, usa -project ios/MyApp.xcodeproj. Compila para el simulador, no un .ipa de dispositivo.

.github/workflows/autonomy-ios.yml
name: Autonomy iOS

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    runs-on: macos-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v5
      - name: Build and zip the simulator app
        run: |
          set -euo pipefail
          xcodebuild \
            -workspace ios/MyApp.xcworkspace \
            -scheme MyApp \
            -configuration Release \
            -sdk iphonesimulator \
            -destination 'generic/platform=iOS Simulator' \
            -derivedDataPath ios/build \
            CODE_SIGNING_ALLOWED=NO \
            build
          mkdir -p .build
          (cd ios/build/Build/Products/Release-iphonesimulator && \
            zip -qry "$GITHUB_WORKSPACE/.build/MyApp.app.zip" MyApp.app)
      - uses: actions/upload-artifact@v5
        with:
          name: ios-simulator-app
          path: .build/MyApp.app.zip
          retention-days: 1

  autonomy:
    needs: build
    runs-on: ubuntu-latest
    timeout-minutes: 35
    steps:
      - uses: actions/checkout@v5
      - uses: actions/download-artifact@v5
        with:
          name: ios-simulator-app
          path: .build
      - name: Run Autonomy
        env:
          AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
          AUTONOMY_TEST_PLAN_ID: ${{ vars.AUTONOMY_TEST_PLAN_ID }}
          APP_IDENTIFIER: ${{ vars.AUTONOMY_IOS_BUNDLE_ID }}
          ARTIFACT_PATH: .build/MyApp.app.zip
          AUTONOMY_REQUEST_ID: github-actions:${{ github.run_id }}:${{ github.run_attempt }}
          AUTONOMY_BRANCH: ${{ github.ref_name }}
          AUTONOMY_COMMIT_SHA: ${{ github.sha }}
        run: bash .ci/autonomy.sh ios

Android

Los builds de Android se hacen en Linux, así que el build y la subida caben en un solo job. Ajusta a la vez la tarea de Gradle y la ruta del APK si usas otro módulo u otra variante de build. Un .aab también funciona.

.github/workflows/autonomy-android.yml
name: Autonomy Android

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  autonomy:
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '17'
      - name: Build the debug APK
        run: |
          set -euo pipefail
          cd android
          ./gradlew --no-daemon assembleDebug
      - name: Run Autonomy
        env:
          AUTONOMY_API_KEY: ${{ secrets.AUTONOMY_API_KEY }}
          AUTONOMY_TEST_PLAN_ID: ${{ vars.AUTONOMY_TEST_PLAN_ID }}
          APP_IDENTIFIER: ${{ vars.AUTONOMY_ANDROID_PACKAGE_NAME }}
          ARTIFACT_PATH: android/app/build/outputs/apk/debug/app-debug.apk
          AUTONOMY_REQUEST_ID: github-actions:${{ github.run_id }}:${{ github.run_attempt }}
          AUTONOMY_BRANCH: ${{ github.ref_name }}
          AUTONOMY_COMMIT_SHA: ${{ github.sha }}
        run: bash .ci/autonomy.sh android

Si el build ya está en un enlace HTTPS de corta duración, puedes omitir la subida: llama a run.trigger con targets.ios.artifactUrl o targets.android.artifactUrl y sourceMode: "url". Consulta Builds móviles.

Condicionar el pipeline al resultado

El script inicia las ejecuciones con POST /api/v1/run.trigger e imprime sus IDs. Un plan de pruebas inicia una ejecución por cada caso de prueba. Después sigue cada ejecución con POST /api/v1/run.get, devolviendo el último cursor con waitMs: 25000, de modo que cada llamada espera hasta que la ejecución cambia. Una respuesta con timedOut: true solo significa que todavía no ha cambiado nada. Consulta Ejecuciones y evidencia.

Resultado de la ejecuciónEl jobQué dice el log
PassedSe supera, si todas las demás ejecuciones también se superaron. Una ejecución superada con reintento (flaky) cuenta como superada.Passed
FailedFalla.Abre la ejecución para ver qué paso falló y por qué, incluido un Runner problem.
Couldn't startFalla.No se pudo probar el entorno, por ejemplo porque el build no se instaló o faltaba un valor. Esto no dice nada de tu app; corrige la causa y vuelve a ejecutar.
CancelledFalla.Cancelled

Los errores de la API, un build que no supera el control de seguridad y agotar el tiempo de espera también hacen fallar el job. AUTONOMY_WAIT_SECONDS es el tiempo de espera total para todas las ejecuciones, 1.200 segundos por defecto. Mantén el límite de tiempo del job de CI por encima de ese valor más el tiempo de build y de subida. Detener el job de CI no cancela las ejecuciones que ya empezaron.

AUTONOMY_REQUEST_ID, con la plataforma añadida, se convierte en el idempotencyKey de run.trigger: si el mismo intento del job vuelve a enviar la petición, recibe las mismas ejecuciones en lugar de otras nuevas. Da a cada intento del job su propio ID. La parte anterior a los primeros dos puntos se envía como proveedor del despliegue, y la rama y el commit acompañan a las ejecuciones. Los formatos completos de petición y respuesta están en Operaciones.

Estrategia de ramas y eventos

Estos workflows se ejecutan con los push a main y cuando se lanzan a mano. Ejecuta planes de smoke cortos en los push habituales, y planes más amplios en ramas de release, programaciones o ejecuciones manuales. Si un plan toca servicios de pago o datos de prueba escasos, lánzalo a mano.

GitHub no da secretos a los workflows de pull requests de forks, así que estos workflows no pueden ejecutarse para ellas. Para tener una ejecución en cada pull request, contra su despliegue de previsualización, usa la GitHub App: consulta Pruebas de pull requests.

Solución de problemas

La ejecución web empieza antes de que la previsualización esté lista

Separa el despliegue y las pruebas en jobs distintos y pasa la URL del despliegue a través de un output del job. Inicia Autonomy solo cuando la URL se conozca y responda.

Se rechaza la subida

El script imprime los motivos del control de seguridad. En iOS, comprueba que el build usó -sdk iphonesimulator y un destino de simulador: un .ipa de dispositivo no puede ejecutarse en un simulador. En Android, sube un .apk o un .aab.

Los pasos que usan valores del entorno no pudieron empezar

Una ejecución con una URL o un build explícitos no tiene entorno. Define AUTONOMY_ENVIRONMENT_SLUG con un entorno guardado, o quita las referencias {{env.NAME}} de esos casos de prueba.

El build de Android no encuentra el SDK

Los runners Ubuntu alojados de GitHub incluyen el SDK de Android. En un runner autoalojado, instala las herramientas de línea de comandos antes del paso de Gradle.

¿No lo encontraste?

On this page