# README — Mobile QA Autonomous Expert

> Guide d'utilisation du prompt `MOBILE-QA-PROMPT.md`  
> Expert autonome en tests d'applications iOS & Android  
> Ruflo v3.5 · Claude Code · Pixel 9 Pro XL · iPhone 17

---

## Ce que fait ce système

Ce prompt transforme Claude Code en expert QA autonome qui :

- Lance et contrôle tes émulateurs/simulateurs AppName intervention manuelle
- Analyse ton code source avant même de lancer l'app (détection statique)
- Navigue dans ton app écran par écran en prenant des décisions seul
- Détecte les bugs UI, UX, accessibilité, performance et crashes
- Génère des rapports professionnels avec screenshots annotés

Les tests Android (Pixel 9 Pro XL) et iOS (iPhone 17) tournent en parallèle via un swarm de 6 agents Ruflo coordonnés.

---

## Prérequis — Vérifier avant le premier lancement

### Outils système

```bash
# Vérifier que tout est installé
adb --version               # Android Debug Bridge
xcrun simctl list           # Xcode CLI tools (macOS uniquement)
idb --version               # idb — interaction simulateur iOS (tap/swipe/type)
idb_companion --version     # idb companion — backend natif requis pour idb
node --version              # Node.js 18+
python3 --version           # Python 3.11+
python3 -c "from PIL import Image; print('OK')"  # Pillow pour annotations
```

Si un outil manque :

```bash
# ADB
brew install android-platform-tools

# Xcode CLI tools
xcode-select --install

# idb (Facebook iOS Development Bridge) — REQUIS pour tap/swipe/type iOS
# ⚠️  xcrun simctl ui ne supporte PAS tap/swipe — idb est indispensable
brew tap facebook/fb
brew install facebook/fb/idb-companion      # binaire natif idb_companion
pip3 install fb-idb --break-system-packages # client Python idb

# Node.js
brew install node

# Python + Pillow
pip3 install pillow --break-system-packages
```

### Ruflo et Claude Code

```bash
# Installer Claude Code
npm install -g @anthropic-ai/claude-code

# Installer et initialiser Ruflo
npx ruflo@latest init --wizard

# Vérifier que les MCP tools Ruflo sont disponibles dans Claude Code
claude --version
```

### Appareils — Confirmer les noms exacts

```bash
# Confirmer le nom exact de ton AVD Android
emulator -list-avds
# Doit afficher : Pixel_9_Pro_XL_API_35 (ou similaire)

# Confirmer le nom exact de ton simulateur iOS
xcrun simctl list devices available | grep "iPhone 17"
# Doit afficher : iPhone 17 (XXXXXXXX-...) (Shutdown)
```

> Si le nom affiché est différent de `Pixel_9_Pro_XL_API_35` ou `iPhone 17`, mets à jour la Phase 0 du prompt (`avd_name` et `ios_device`).

### Clé API Anthropic

```bash
# Vérifier que la clé est configurée
echo $ANTHROPIC_API_KEY

# Si vide, l'ajouter dans ton shell
export ANTHROPIC_API_KEY="sk-ant-..."
# Ou l'ajouter définitivement dans ~/.zshrc ou ~/.bashrc
```

---

## Installation — Première fois

```bash
# 1. Cloner ou copier ce dossier dans ton projet
cp MOBILE-QA-PROMPT.md /chemin/vers/ton/projet/
cp README-QA.md /chemin/vers/ton/projet/

# 2. Se placer à la racine du projet app
cd /chemin/vers/ton/projet/

# 3. Créer le dossier de rapports
mkdir -p qa-reports

# 4. Initialiser Ruflo dans ce projet
npx ruflo@latest init --wizard
# Suivre les instructions → accepter les defaults
```

---

## Personnalisation du prompt — 6 variables à remplacer

Ouvre `MOBILE-QA-PROMPT.md` et remplace ces valeurs avant chaque lancement :

| Variable              | Où la trouver                                | Exemple                       |
| --------------------- | -------------------------------------------- | ----------------------------- |
| `{APP_ID_ANDROID}`    | `android/app/build.gradle` → `applicationId` | `com.monapp.android`          |
| `{APP_ID_IOS}`        | `ios/App/Info.plist` → `CFBundleIdentifier`  | `com.monapp.ios`              |
| `{APP_NAME}`          | Nom commercial de ton app                    | `MonApp v2.3`                 |
| `{CRITICAL_FLOWS}`    | Les flows les plus importants de ton app     | `auth, paiement, profil`      |
| `{SLACK_WEBHOOK_URL}` | Slack → Apps → Incoming Webhooks             | `https://hooks.slack.com/...` |
| `{ACTION_BUDGET}`     | Nombre max d'actions par plateforme          | `50` (défaut)                 |

> `avd_name` et `ios_device` sont déjà configurés pour ton setup (Pixel 9 Pro XL + iPhone 17). Ne pas modifier.

---

## Lancement — 3 modes d'utilisation

### Mode 1 — Audit complet (recommandé)

Lance les deux plateformes en parallèle, tous les flows, rapport complet.

```bash
claude --dangerously-skip-permissions \
  "Exécute le plan QA mobile complet défini dans MOBILE-QA-PROMPT.md.
   App cible : com.monapp.android (Android) / com.monapp.ios (iOS).
   Produis tous les rapports dans ./qa-reports/."
```

Durée estimée : **15 à 25 minutes** selon la taille de l'app.  
Coût API estimé : **$0.30 à $0.80** selon le nombre d'écrans.

---

### Mode 2 — Android uniquement (plus rapide)

```bash
claude --dangerously-skip-permissions \
  "Exécute le plan QA mobile du fichier MOBILE-QA-PROMPT.md.
   Plateforme : Android uniquement (Pixel 9 Pro XL).
   App : com.monapp.android.
   Saute toutes les étapes iOS.
   Rapports dans ./qa-reports/."
```

Durée estimée : **8 à 12 minutes.**

---

### Mode 3 — Flow spécifique uniquement

Pour tester un seul flow après une correction ou une nouvelle feature.

```bash
claude --dangerously-skip-permissions \
  "Exécute le plan QA mobile du fichier MOBILE-QA-PROMPT.md.
   Plateforme : Android et iOS.
   App : com.monapp.android / com.monapp.ios.
   Teste UNIQUEMENT le flow : authentification (inscription + connexion + mot de passe oublié).
   Ignore les autres flows.
   Rapports dans ./qa-reports/."
```

Durée estimée : **4 à 7 minutes.**

---

### Mode 4 — Régression rapide (pré-release)

```bash
claude --dangerously-skip-permissions \
  "Exécute le plan QA mobile du fichier MOBILE-QA-PROMPT.md.
   Plateforme : Android et iOS.
   App : com.monapp.android / com.monapp.ios.
   Mode régression : exécute uniquement les 5 scénarios de la Phase 4.
   Budget réduit : 20 actions par plateforme.
   Rapports dans ./qa-reports/."
```

Durée estimée : **6 à 10 minutes.**

---

## Structure des rapports générés

Après chaque session, le dossier `./qa-reports/` contient :

```
qa-reports/
├── rapport-qa.md              ← Rapport Markdown complet (pour l'équipe)
├── rapport-qa.json            ← Données structurées (pour CI/CD)
├── alerte-slack.json          ← Payload Slack (envoyé auto si bugs critiques)
├── screenshots/
│   ├── screen_android_001.png       ← Capture brute
│   ├── screen_android_001_bug_ANDROID-001.png  ← Annoté avec le bug
│   ├── screen_ios_001.png
│   └── screen_ios_001_bug_IOS-001.png
└── logs/
    ├── crash_android_001.log  ← Logs de crash Android (si crash détecté)
    └── crash_ios_001.log      ← Logs de crash iOS (si crash détecté)
```

---

## Intégration CI/CD — GitHub Actions

Ajoute ce fichier dans ton repo pour un test automatique à chaque PR :

```yaml
# .github/workflows/mobile-qa.yml
name: Mobile QA Autonome

on:
  pull_request:
    branches: [main, develop]
  schedule:
    - cron: "0 2 * * 1-5" # Lundi au vendredi à 2h du matin

jobs:
  qa-audit:
    runs-on: macos-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: |
          npm install -g @anthropic-ai/claude-code
          npx ruflo@latest init
          pip install pillow

      - name: Start Android Emulator
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 35
          profile: pixel_9_pro_xl
          arch: x86_64

      - name: Run QA Agent
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --dangerously-skip-permissions \
            "Exécute MOBILE-QA-PROMPT.md. App : ${{ vars.APP_BUNDLE_ID }}. Rapports dans ./qa-reports/."

      - name: Post QA Report on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs')
            const report = fs.readFileSync('./qa-reports/rapport-qa.md', 'utf8')
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: report
            })

      - name: Upload screenshots
        uses: actions/upload-artifact@v4
        with:
          name: qa-screenshots
          path: qa-reports/screenshots/
```

---

## Optimisation des coûts API

Par défaut, le prompt utilise `claude-sonnet-4-20250514` pour toutes les analyses. Pour réduire les coûts :

### Option 1 — Triage Haiku (économie ~60%)

Ajoute cette instruction dans la Phase 3 du prompt :

```
Pour l'étape B d'analyse de chaque screenshot :
- Utiliser claude-haiku-4-5-20251001 pour un premier triage : "Y a-t-il un bug visible ? OUI ou NON"
- Utiliser claude-sonnet-4-20250514 UNIQUEMENT si Haiku répond OUI
```

### Option 2 — Prompt caching (économie ~40% sur les sessions longues)

Le contexte système (SYSTEM_PROMPT) est identique pour tous les appels d'analyse.  
Ajouter `cache_control: { type: "ephemeral" }` sur le system prompt dans le SDK Python.

### Option 3 — Budget réduit

Remplacer `ACTION_BUDGET: 50` par `ACTION_BUDGET: 25` pour les apps de taille moyenne.

### Estimation des coûts par mode

| Mode                              | Durée  | Coût estimé        |
| --------------------------------- | ------ | ------------------ |
| Audit complet (Android + iOS)     | 20 min | $0.40 – $0.80      |
| Android uniquement                | 10 min | $0.15 – $0.35      |
| Flow spécifique                   | 5 min  | $0.05 – $0.15      |
| Régression rapide                 | 8 min  | $0.10 – $0.25      |
| Session quotidienne (10 sessions) | —      | $1.00 – $4.00/jour |

---

## Résolution des problèmes courants

### L'émulateur Android ne démarre pas

```bash
# Vérifier que le nom AVD est correct
emulator -list-avds

# Démarrer manuellement et attendre
emulator -avd Pixel_9_Pro_XL_API_35 -no-snapshot -no-audio &
adb wait-for-device
adb shell getprop sys.boot_completed
# Doit retourner "1"
```

### Le simulateur iOS ne démarre pas

```bash
# Lister tous les simulateurs disponibles
xcrun simctl list devices

# Si "iPhone 17" n'apparaît pas, le créer
xcrun simctl create "iPhone 17" "iPhone 17" "iOS-18-0"

# Booter manuellement
xcrun simctl boot "iPhone 17"
open -a Simulator
```

### idb ne peut pas se connecter au simulateur

```bash
# 1. Vérifier que idb_companion est installé
idb_companion --version   # doit afficher {"build_time":"...", "build_date":"..."}

# 2. Démarrer idb_companion manuellement en arrière-plan
UDID=$(xcrun simctl list devices booted | grep "iPhone 17" | grep -oE '[A-F0-9-]{36}')
idb_companion --udid $UDID --grpc-port 10882 &

# 3. Connecter le client Python
idb connect 127.0.0.1 10882

# 4. Vérifier la liste des appareils
idb list-targets

# 5. Tester un tap (vérifier le résultat avec screenshot)
idb ui tap --udid $UDID 195 400
xcrun simctl io booted screenshot /tmp/test_tap.png && open /tmp/test_tap.png
```

> **Note importante (découverte en session)** : `xcrun simctl ui booted tap/swipe` n'existe **pas** sur Xcode 15+. `idb` est la seule solution officielle pour l'interaction dynamique sur iOS simulateur sans Appium.

### Ruflo n'est pas reconnu par Claude Code

```bash
# Réinitialiser Ruflo
npx ruflo@latest init --wizard --force

# Vérifier les MCP servers configurés
cat ~/.claude/claude_desktop_config.json | grep ruflo
```

### Les screenshots ne sont pas capturés

```bash
# Android — tester la commande manuellement
adb exec-out screencap -p > /tmp/test.png
open /tmp/test.png  # doit ouvrir l'image

# iOS — tester la commande manuellement
xcrun simctl io booted screenshot /tmp/test_ios.png
open /tmp/test_ios.png
```

### L'arbre UI Android est trop volumineux (> 8000 tokens)

Ajouter cette instruction dans la Phase 3 du prompt :

```bash
# Filtrer l'arbre UI avant envoi — garder uniquement les éléments interactifs
adb shell uiautomator dump /sdcard/ui.xml
adb pull /sdcard/ui.xml /tmp/ui.xml
python3 -c "
import xml.etree.ElementTree as ET
tree = ET.parse('/tmp/ui.xml')
# Garder uniquement les éléments clickable ou focusable
nodes = [n for n in tree.iter() if n.get('clickable')=='true' or n.get('focusable')=='true']
print(ET.tostring(nodes[:50], encoding='unicode'))
" > /tmp/ui_filtered.xml
```

### idb — Obtenir l'arbre d'accessibilité iOS (alternative à uiautomator)

```bash
UDID=$(xcrun simctl list devices booted | grep "iPhone 17" | grep -oE '[A-F0-9-]{36}')

# Décrire tous les éléments accessibles à l'écran
idb ui describe-all --udid $UDID 2>/dev/null | python3 -c "
import sys, json
data = json.load(sys.stdin)
elements = data.get('elements', [])[:50]  # Limiter à 50 éléments
print(json.dumps(elements, indent=2))
" > /tmp/ui_ios.json
```

---

## Commandes idb — Référence rapide iOS Simulator

Toutes les commandes nécessitent que `idb_companion` soit démarré et connecté (voir section troubleshooting ci-dessus).

```bash
UDID="[Simulateur_iOS_UDID]"  # iPhone 17 AppName

# --- Interaction ---
idb ui tap --udid $UDID {x} {y}                       # Tap
idb ui swipe --udid $UDID {x1} {y1} {x2} {y2} {durée} # Swipe (durée en secondes, ex: 0.3)
idb ui text --udid $UDID 'texte à saisir'             # Saisie texte
idb ui button --udid $UDID HOME                       # Bouton HOME
idb ui button --udid $UDID LOCK                       # Verrouiller

# --- Capture ---
idb screenshot --udid $UDID /tmp/screen.png           # Screenshot
idb record-video --udid $UDID /tmp/video.mp4 &        # Enregistrement vidéo (Ctrl+C pour stopper)

# --- App ---
idb launch --udid $UDID example.com.app  # Lancer l'app
idb terminate --udid $UDID example.com.app # Terminer l'app
idb install --udid $UDID /path/to/Runner.app          # Installer un build

# --- Accessibilité ---
idb ui describe-all --udid $UDID                      # Arbre d'accessibilité complet
idb ui describe-point --udid $UDID {x} {y}           # Élément à un point précis

# --- Système ---
idb set-location --udid $UDID 48.8566 2.3522          # Simuler une position GPS (Paris)
idb approve --udid $UDID example.com.app photos camera location  # Approuver permissions
```

---

## Bonnes pratiques

**Avant de lancer :**

- Démarrer `idb_companion` en arrière-plan avant la session (voir commandes ci-dessus)
- Fermer toutes les autres apps sur les émulateurs/simulateurs
- S'assurer que l'app est déjà installée sur les deux appareils
- Avoir une connexion internet stable (les appels Claude API sont nombreux)
- Créer le dossier `./qa-reports/` s'il n'existe pas

**Pour de meilleurs résultats :**

- Préciser les flows critiques de ton app dans `{CRITICAL_FLOWS}` — l'agent les priorisera
- Lancer d'abord en Mode 2 (Android uniquement) pour valider le setup, puis passer au Mode 1
- Conserver les rapports JSON de chaque session pour suivre les tendances de qualité dans le temps
- Utiliser `idb ui describe-all` pour obtenir les coordonnées exactes des éléments UI avant de tapper

**Ce que le système ne fait pas :**

- Tester les gestes multi-touch (pinch-to-zoom) — non supporté par ADB/idb
- Tester les achats in-app réels (sandbox uniquement)
- Créer des AVDs ou simulateurs s'ils n'existent pas encore (les créer manuellement une fois)
- Tester sur des appareils physiques sans configuration ADB/idb supplémentaire

---

## Support et références

- **Ruflo (Claude Flow v3.5)** : https://github.com/ruvnet/ruflo
- **Claude Code** : https://www.anthropic.com/product/claude-code
- **idb (Facebook iOS Dev Bridge)** : https://github.com/facebook/idb
- **idb — commandes UI** : `idb ui --help` (tap, swipe, text, button, describe-all)
- **ADB référence** : https://developer.android.com/tools/adb
- **xcrun simctl référence** : https://developer.apple.com/documentation/xcode/simctl
- **Appium (alternative)** : https://appium.io
- **Allure Reports** : https://allurereport.org
