Présentation
L'API CI de Thunders vous permet de mettre en file d'attente des exécutions de tests, d'interroger leur état et de récupérer des rapports structurés (JUnit XML ou JSON), le tout via 3 points de terminaison situés sous /api/ci/.
Quand vous testez une application mobile, le même pipeline peut aussi téléverser chaque nouveau build avant de mettre les exécutions en file d'attente. Consultez la section Téléverser un build d'application mobile plus bas.
Points de terminaison de l'API
POST https://api.thunders.ai/api/ci/run
GET https://api.thunders.ai/api/ci/run/{runId}
GET https://api.thunders.ai/api/ci/run/{runId}/report
Authentification
L'API nécessite une authentification à l'aide d'un jeton Bearer :
Authorization: Bearer YOUR_THUNDER_TEST_TOKEN
Vous devez obtenir un jeton API valide auprès de la plateforme Thunders. Ce jeton doit être stocké en toute sécurité en tant que secret dans votre environnement ou votre dépôt GitHub.
Où trouver votre jeton API
Les jetons API appartiennent à l'organisation plutôt qu'à un projet spécifique ; un même jeton fonctionne donc pour tous les projets de cette organisation. Vous devez disposer d'un rôle d'administrateur pour en créer un.
Sélectionnez le nom de votre organisation en haut de la barre latérale gauche pour ouvrir le menu de l'organisation.
Sélectionnez Paramètres.
Sélectionnez Jetons API. La page Jetons API de l'organisation répertorie tous les jetons avec leur statut, leur date de création et le nom de leur créateur.
Créez un nouveau jeton, puis confirmez lorsque le message "Êtes-vous sûr de vouloir créer un nouveau jeton API ?" s'affiche.
Sélectionnez Afficher pour révéler le nouveau jeton, puis Copier.
Collez-le directement dans votre magasin de secrets. Traitez-le comme un mot de passe, car toute personne en possession de ce jeton peut mettre en file d'attente des exécutions au nom de votre organisation.
Pour révoquer un jeton, sélectionnez Révoquer dans la ligne correspondante. La révocation est irréversible, et tout pipeline utilisant encore ce jeton recevra une erreur 401 Unauthorized ; veillez donc à émettre un jeton de remplacement au préalable.
En savoir plus : Créer / Révoquer un jeton API
En-têtes
En-tête | Valeur | Description |
|
| Jeton d'authentification |
|
| Indique un appel API de machine à machine |
|
| Spécifie le format du corps de la requête |
POST /api/ci/run — Mettre en file d'attente des exécutions
Met en file d'attente les exécutions d'un ou plusieurs cas de test et/ou groupes de test. Toutes les exécutions sont regroupées sous un runId commun. Renvoie des URL que vous pouvez utiliser pour interroger l'état d'avancement et récupérer le rapport final.
Corps de la requête
Au moins l'un des paramètres testCaseIds ou testSetIds doit être fourni. Les deux peuvent être fournis dans la même requête ; dans ce cas, les deux seront exécutés.
Exemple
{
"projectId": "c8e34ec4-2464-43c7-8db8-1b3a47a22337",
"testCaseIds": ["a836fadc-377a-46fe-96b0-21f37c626bf9"],
"testSetIds": ["8eea2fd3-da6d-4434-a310-176be84c5646"],
"environmentId": "eca24252-e566-40a8-b2b0-707b7efa85d8",
"personaId": "70d0ac52-fe94-4d89-aba9-8ef28dd8c04c",
"maxParallelism": 5,
"maxRetries": 1,
"browserSettings": { "location": "Paris", "resolution": "1440x900", "deviceType": "Desktop" }
}
Paramètres
Paramètre | Type | Obligatoire | Valeur par défaut | Description |
|
| Oui | - | Identifiant unique du projet. |
|
| Non | - | Liste des identifiants des cas de test à exécuter. |
|
| Non | - | Liste des identifiants des groupes de test. Chaque groupe se décompose en ses cas de test. |
|
| Oui | - | L'environnement à utiliser. |
|
| Oui | - | La Persona utilisée pour l'exécution du test. |
|
| Non | 4 | Nombre maximal de tests en parallèle. |
|
| Non | 0 | Nombre de nouvelles tentatives pour les tests en échec (0-3). |
|
| Non |
|
|
|
| Non |
|
|
|
| Non | main | La branche dont les tests s'exécutent. Consultez la section Exécuter les tests d'une branche plus bas. |
|
| Non | - | Références des ressources de test pour l'exécution par lots. |
|
| Non |
| Cluster géographique : Paris, London, Amsterdam, SanFrancisco, NewYork. |
|
| Non |
| Chromium, Chrome, Firefox ou Safari. |
|
| Non |
| Desktop, Mobile ou Tablet. |
|
| Non |
| Résolution de la fenêtre d'affichage (par exemple "1440x900"). |
Réponse — 202 Accepted
{
"runId": "01966a3e-...",
"statusUrl": "/api/ci/run/01966a3e-...",
"reportUrl": "/api/ci/run/01966a3e-.../report"
}
GET /api/ci/run/{runId} — Interroger l'état de l'exécution
Renvoie l'état agrégé de toutes les exécutions de test. Interrogez jusqu'à ce que status soit définitif (passed, failed, stopped, cancelled).
Réponse — 200 OK
{
"runId": "01966a3e-...",
"status": "running",
"testCount": 5,
"passedCount": 2,
"failedCount": 0,
"runningCount": 2,
"queuedCount": 1,
"startedAt": "2026-03-20T14:30:00Z",
"endedAt": null,
"durationMs": null
}
GET /api/ci/run/{runId}/report — Récupérer le rapport
Renvoie le rapport d'exécution du test. Le format dépend de l'en-tête Accept :
Par défaut (ou
application/xml) : JUnit XML, compatible avec Jenkins, GitHub Actions (dorny/test-reporter), GitLab et d'autres.Accept: application/json: rapport JSON avec des données structurées.
Exécuter les tests d'une branche
Une exécution CI utilise les tests de main, sauf si vous indiquez une autre branche. Pour exécuter la version des tests d'une branche, ajoutez branchId au corps de la requête :
{
"projectId": "c8e34ec4-2464-43c7-8db8-1b3a47a22337",
"testSetIds": ["8eea2fd3-da6d-4434-a310-176be84c5646"],
"environmentId": "eca24252-e566-40a8-b2b0-707b7efa85d8",
"personaId": "70d0ac52-fe94-4d89-aba9-8ef28dd8c04c",
"branchId": "0199b2c4-7e1a-7c3d-9f20-5a6b8c9d0e1f"
}L'exécution utilise les étapes et les paramètres que les tests ont sur cette branche.
Les champs
statusUrletreportUrlde la réponse portent le mêmebranchId. Utilisez-les tels que la réponse les renvoie.L'API refuse une branche fusionnée, abandonnée ou d'un autre projet de test, avec
400 Bad Request. Elle n'exécute jamais main à sa place.Sans
branchId, l'exécution utilise main : vos pipelines existants ne changent pas.
Pour trouver l'identifiant d'une branche, listez les branches actives du projet de test avec le même jeton et les mêmes en-têtes :
GET https://api.thunders.ai/api/branches?projectId={projectId}Chaque branche de la réponse porte son id et son name. main figure toujours dans la liste.
Pour créer une branche et la fusionner dans Thunders, consultez Comment modifier mes tests sur une branche et les fusionner dans main ?
Gestion des erreurs
L'API utilise les codes d'état HTTP standard :
202 Accepted:POST /api/ci/run— les tests ont été mis en file d'attente avec succès200 OK: points de terminaisonGET— la requête a abouti400 Bad Request: requête mal formée ou paramètres obligatoires manquants401 Unauthorized: échec de l'authentification ou jeton invalide403 Forbidden: autorisations insuffisantes404 Not Found: aucune exécution de test trouvée pour lerunIdindiqué500 Internal Server Error: erreur inattendue du serveur
Utilisation avec GitHub Actions
Intégrez l'API CI de Thunders à GitHub Actions pour automatiser l'exécution des tests dans votre pipeline CI/CD.
Exemple de workflow GitHub Actions
name: Run Thunders Tests
on:
workflow_dispatch:
permissions:
contents: read
checks: write
jobs:
run-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Queue Thunders CI Run
id: trigger
run: |
set -euo pipefail
RESP=$(curl -sS --fail-with-body -X POST https://api.thunders.ai/api/ci/run \
-H "Authorization: Bearer ${{ secrets.THUNDER_TEST_TOKEN }}" \
-H "X-MS-API-ROLE: M2M" \
-H "Content-Type: application/json" \
-d '{"projectId":"YOUR_PROJECT_ID","testSetIds":["YOUR_TEST_SET_ID"],"environmentId":"YOUR_ENVIRONMENT_ID","personaId":"YOUR_PERSONA_ID","maxParallelism":5,"maxRetries":1}')
echo "status_url=$(echo "$RESP" | jq -r '.statusUrl')" >> $GITHUB_OUTPUT
echo "report_url=$(echo "$RESP" | jq -r '.reportUrl')" >> $GITHUB_OUTPUT
- name: Wait for completion
id: run-tests
run: |
set -euo pipefail
MAX_WAIT=5400; INTERVAL=30; ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
RESP=$(curl -sS --fail-with-body \
"https://api.thunders.ai${{ steps.trigger.outputs.status_url }}" \
-H "Authorization: Bearer ${{ secrets.THUNDER_TEST_TOKEN }}" \
-H "X-MS-API-ROLE: M2M")
STATUS=$(echo "$RESP" | jq -r '.status')
echo "[$ELAPSED s] status=$STATUS"
case "$STATUS" in
passed|failed|stopped|cancelled)
echo "final_status=$STATUS" >> $GITHUB_OUTPUT; break;;
esac
sleep $INTERVAL; ELAPSED=$((ELAPSED+INTERVAL))
done
- name: Download JUnit report
run: |
curl -sS --fail-with-body \
"https://api.thunders.ai${{ steps.trigger.outputs.report_url }}" \
-H "Authorization: Bearer ${{ secrets.THUNDER_TEST_TOKEN }}" \
-H "X-MS-API-ROLE: M2M" \
-o test-results.xml
- name: Publish test results
uses: dorny/test-reporter@v1
continue-on-error: true
with:
name: Thunders CI Results
path: test-results.xml
reporter: java-junit
- name: Fail if tests did not pass
if: steps.run-tests.outputs.final_status != 'passed'
run: exit 1
Configuration des secrets GitHub
Accédez à votre dépôt GitHub
Accédez à Settings, puis Secrets and variables, puis Actions
Cliquez sur "New repository secret"
Nom :
THUNDER_TEST_TOKENValeur : votre jeton API Thunders
Cliquez sur "Add secret"
Lot de ressources de test
La fonctionnalité Lot de ressources de test vous permet d'exécuter plusieurs fois le même cas de test avec différentes variations de données, en important des fichiers CSV en tant que ressources de test. Chaque ligne du fichier CSV correspond à une exécution distincte, ce qui permet de réaliser des tests pilotés par les données à grande échelle.
Fonctionnement
Importez des fichiers CSV en tant que ressources de test dans votre projet (via l'application web Thunders ou l'API)
Référencez les fichiers CSV dans votre requête API à l'aide du paramètre
testAssetReferencesChaque ligne du fichier CSV génère une exécution distincte avec ses propres remplacements de variables et ses propres paramètres de navigateur
Toutes les exécutions d'un même lot sont regroupées sous un
batchIdcommun
Avec executionMode: sequential, chaque ligne du fichier CSV s'exécute comme une chaîne indépendante : les cas de test d'une même ligne s'exécutent un par un dans l'ordre alphabétique, tandis que les lignes s'exécutent en parallèle. maxParallelism limite le nombre de lignes s'exécutant simultanément. failureBehavior: stop s'applique à une seule ligne.
Le paramètre testAssetReferences
Ajoutez le champ testAssetReferences au corps de votre requête :
{
"projectId": "your-project-id",
"testCaseIds": ["your-test-case-id"],
"environmentId": "your-environment-id",
"personaId": "your-persona-id",
"testAssetReferences": ["FILE_MYDATA_CSV", "FILE_USERS_CSV"]
}Format de référence : lorsque vous importez un fichier nommé mydata.csv, sa référence devient FILE_MYDATA_CSV. La convention de nommage est FILE_<NOM_FICHIER>_<EXT>, le nom du fichier étant en majuscules et les caractères spéciaux remplacés par des traits de soulignement.
Pour en savoir plus sur la fonctionnalité de traitement par lots, consultez cette documentation
Combiner plusieurs fichiers CSV
Vous pouvez passer plusieurs références CSV dans le tableau testAssetReferences. Les lignes de tous les fichiers sont fusionnées séquentiellement en un seul lot avec un indexage continu.
Si browsers.csv comporte 3 lignes et mobile.csv 2 lignes, le lot contiendra au total 5 exécutions indexées de 1 à 5.
Téléverser un build d'application mobile
Quand vous testez une application mobile, votre pipeline peut envoyer chaque nouvel APK ou IPA à Thunders avant de mettre les exécutions en file d'attente. Le téléversement remplace le build de cette application dans un environnement, et l'exécution suivante l'installe. Une exécution déjà démarrée se termine sur le build avec lequel elle a démarré.
GET https://api.thunders.ai/api/projects/{projectId}/apps
POST https://api.thunders.ai/api/apps/{appId}/buildsLes deux points de terminaison utilisent le même jeton API et les mêmes en-têtes Authorization et X-MS-API-ROLE: M2M que les points de terminaison CI ci-dessus.
Trouver les identifiants de l'application et de l'environnement
GET /api/projects/{projectId}/apps liste les applications d'un projet de test. Chaque application porte son id et un tableau environments, avec l'environmentId et l'environmentName de chaque environnement et le build qu'il contient. Copiez ces deux identifiants une fois dans votre pipeline.
Téléverser le build
POST /api/apps/{appId}/builds attend un corps multipart/form-data au lieu de JSON.
Champ | Type | Obligatoire | Description |
|
| Oui | Le projet de test qui contient l'application. |
|
| Oui | L'environnement dont le build est remplacé. |
| fichier | Oui | Un fichier |
Réponse, 200 OK
{
"fileName": "app-release.apk",
"fileSizeBytes": 14200000,
"platform": "android",
"source": "ci",
"uploadedAt": "2026-10-13T09:30:00Z",
"appPackage": "com.acme.shop",
"appVersion": "2.4.1",
"appBuildNumber": "241"
}Champ | Type | Description |
|
|
|
|
|
|
|
| Le nom de package Android ou le bundle id iOS, lu dans le fichier. |
|
|
|
|
|
|
Chaque exécution sur une application mobile enregistre la version et le numéro du build qu'elle a installé, et son rapport les affiche dans la ligne Build de l'application.
Erreurs
400 Bad Request: aucun fichier, un fichier vide, un fichier autre que.apkou.ipa, ou un build dont le nom de package est illisible401 Non autorisé: le jeton est absent ou invalide404 Non trouvé: l'application ou l'environnement n'existe pas dans ce projet de test, ou appartient à une autre organisation413 Payload Too Large: le fichier dépasse 500 Mo
Exemple d'étape GitHub Actions
Ajoutez cette étape avant celle qui met les exécutions en file d'attente :
- name: Upload the new build to Thunders
run: |
curl --fail-with-body -sS -X POST \
"https://api.thunders.ai/api/apps/YOUR_APP_ID/builds" \
-H "Authorization: Bearer ${{ secrets.THUNDER_TEST_TOKEN }}" \
-H "X-MS-API-ROLE: M2M" \
-F "projectId=YOUR_PROJECT_ID" \
-F "environmentId=YOUR_ENVIRONMENT_ID" \
-F "file=@app/build/outputs/apk/release/app-release.apk"
--fail-with-body arrête le job en cas d'erreur et affiche le message qui l'explique.
Lorsque vous n'avez pas besoin d'un pipeline
Si vous souhaitez simplement qu'un groupe de test s'exécute selon une règle récurrente, un Planning s'en charge dans Thunders, sans pipeline à maintenir ni jeton à renouveler. Ouvrez le groupe de test, sélectionnez l'onglet Plannings, puis choisissez l'une des cinq fréquences, de Chaque heure à Mensuel.
Continuez à utiliser la CI lorsque l'exécution doit avoir lieu à un moment précis de votre processus de livraison, par exemple après un déploiement ou sur une pull request, ou lorsque vous avez besoin d'une exécution plus fréquente qu'une fois par heure. Chaque heure est l'intervalle le plus court pris en charge par un Planning.
