Périmètre sûr : ce guide s'applique uniquement à vos propres applications, en QA, en préproduction ou en production, ou à des systèmes pour lesquels vous détenez une autorisation écrite. Il ne traite ni de l'automatisation de sites tiers, ni de la résolution de protections que vous ne contrôlez pas.
Un test XCUITest ne peut pas résoudre un reCAPTCHA v2 tout seul : le framework pilote l'interface, mais il n'exécute pas de JavaScript à l'intérieur d'une WKWebView. La réponse tient en trois temps : détecter le défi dans la WebView, déléguer la résolution à CaptchaAI depuis une étape externe, puis réinjecter le token dans la page pour que le formulaire se soumette. Vos parcours de connexion et d'inscription redeviennent alors testables de bout en bout, sans intervention manuelle.
Pourquoi le CAPTCHA bloque vos suites XCUITest
XCUITest interagit avec des éléments d'interface : boutons, champs de texte, libellés d'accessibilité. Il ne voit pas le DOM d'une WebView et ne peut donc ni lire le data-sitekey, ni écrire dans le champ g-recaptcha-response. Résultat : dès qu'un écran embarque un reCAPTCHA v2, le test se fige et le pipeline se termine en échec ou en timeout.
La solution consiste à confier la partie « web » à un composant capable d'exécuter du JavaScript dans la WebView, et la résolution proprement dite à CaptchaAI. XCUITest reste le chef d'orchestre : il déclenche l'étape, attend le signal de fin, puis poursuit le parcours.
Architecture : la résolution pilotée depuis une étape externe
Le principe est de séparer trois responsabilités :
- XCUITest pilote l'interface et déclenche la résolution via un hook de test présent uniquement dans le build de debug.
- Un service externe (un script Python lancé sur la machine de test, ou une étape Fastlane) reçoit le sitekey et l'URL de la page, appelle CaptchaAI, puis renvoie le token.
- CaptchaAI résout le défi reCAPTCHA v2 et retourne le token via son API.
Concrètement, le hook de test lit le data-sitekey avec un sélecteur .g-recaptcha, remonte l'URL courante et transmet ces deux valeurs au service externe. Celui-ci appelle CaptchaAI, récupère le token, puis l'injecte dans la WebView via evaluateJavaScript.
Injecter le token dans la WKWebView
Une fois le token obtenu, l'injection se réduit à écrire sa valeur dans le champ g-recaptcha-response de la page — l'unique point de contact entre votre code de test et le formulaire protégé.
Exemple Swift d'injection du token :
func injectCaptchaToken(_ token: String, into webView: WKWebView) {
let js = "document.getElementById('g-recaptcha-response').value = \"\(token)\";"
webView.evaluateJavaScript(js)
}
Si le formulaire s'appuie sur un callback reCAPTCHA plutôt que sur une simple lecture de champ, déclenchez-le après l'écriture du token. Isolez tout ce code de hook derrière une directive #if DEBUG : le pont de test ne doit jamais partir en release.
Sécuriser la clé et les secrets
Conservez votre clé CaptchaAI dans le keychain de votre CI (ou un coffre à secrets), jamais dans le code source. Exposez-la au service externe via une variable d'environnement à l'exécution. Cette discipline vaut aussi pour vos machines de développement : une clé qui fuit dans un dépôt Git reste exploitable même après un git revert.
Côté facturation, l'API CaptchaAI est facturée au thread concurrent, pas à la résolution. Si vous lancez plusieurs simulateurs en parallèle, dimensionnez le plan sur le nombre de tests simultanés : le palier BASIC ($15/mois, 5 threads) couvre une suite modeste, tandis qu'un pipeline plus parallélisé justifiera STANDARD ($30/mois, 15 threads).
Observabilité et journalisation
Quel que soit le langage de votre service externe, instrumentez les appels CAPTCHA pour obtenir des métriques exploitables : durée totale d'obtention du token, code retour HTTP, identifiant de tâche et taille de la file d'attente. Ces signaux alimentent vos tableaux de bord de QA et déclenchent une alerte quand un temps de résolution dérive.
Séparez les journaux par environnement (développement, préproduction, production) et conservez les identifiants corrélés à votre traçage distribué, par exemple via OpenTelemetry : vous pourrez rejouer un scénario complet à partir d'un identifiant unique et réduire le temps de diagnostic en cas d'incident. Pensez aussi à minimiser les données personnelles écrites dans les logs de test : un parcours d'inscription manipule des adresses e-mail et des identifiants, et vos obligations RGPD s'appliquent même en préproduction.
Un scénario concret
Prenons une fintech basée à Paris dont l'application iOS ouvre son formulaire d'inscription dans une WKWebView, protégé par un reCAPTCHA v2. Sa suite XCUITest tourne sur des runners macOS hébergés dans la région eu-west-3 (Paris) pour limiter la latence réseau.
Avant l'intégration de CaptchaAI, chaque exécution nocturne échouait sur l'écran d'inscription : impossible de valider le parcours jusqu'à la confirmation de compte. En déléguant la résolution à une étape externe et en réinjectant le token, l'équipe a retrouvé un test de bout en bout stable. Le périmètre reste strictement interne : application maison, comptes de test dédiés, aucune donnée réelle d'utilisateur.
Liste de contrôle avant exécution
-
Le périmètre est strictement limité à vos propres applications ou à des sources autorisées.
-
La clé CaptchaAI est stockée dans un secret CI ou un coffre, jamais dans le code source.
-
Le hook de test est isolé derrière
#if DEBUGet absent des builds de production. -
Les durées d'appel et les codes retour sont tracés pour chaque exécution.
-
Une stratégie de retry idempotent est en place pour les erreurs transitoires.
-
Les tests sont rejouables et reproductibles depuis votre intégration continue.
FAQ
Comment XCUITest peut-il gérer un CAPTCHA dans une WKWebView ?
Indirectement. XCUITest pilote l'interface mais n'exécute pas de JavaScript dans une WebView. Ajoutez un hook de test dans le build de debug qui lit le sitekey, appelle CaptchaAI depuis une étape externe, puis écrit le token dans le champ g-recaptcha-response. XCUITest se contente de déclencher ce flux et d'attendre la fin.
Quel timeout prévoir pour un test qui résout un CAPTCHA ?
Dimensionnez-le largement. La résolution dépend du type de défi et de la charge du moment ; un test qui attend un reCAPTCHA v2 doit tolérer plusieurs dizaines de secondes. Réglez le timeout XCUITest sur 120 secondes ou plus, sinon vos tests échoueront alors que la résolution était encore en cours.
Comment éviter que le hook de test parte en production ?
Enveloppez tout le code du pont de test dans des directives #if DEBUG. Le compilateur les retire des builds de release : ni le détecteur de sitekey, ni le service d'injection ne se retrouvent dans le binaire distribué sur l'App Store.
Que faire si l'API renvoie une erreur transitoire ?
Mettez en place un retry avec backoff exponentiel borné : par exemple trois tentatives, doublement du délai à chaque essai, plafond à 30 secondes. Tracez chaque échec avec son identifiant de tâche pour le diagnostic. Si l'erreur persiste, vérifiez la configuration réseau (DNS, certificats) et les quotas de votre clé.
Guides connexes
- Le démarrage rapide CaptchaAI
- La QA CAPTCHA en environnements autorisés
- Tester l'endpoint API sur vos formulaires
- Intégrer la résolution CAPTCHA en CI
- Résoudre reCAPTCHA v2 via l'API
- Résoudre Cloudflare Turnstile via l'API
Fiabilisez vos parcours de test CAPTCHA dans vos propres environnements avec une méthode reproductible. – Obtenez votre clé CaptchaAI.