Suite de tests système mobiles (iOS + Android) et webapp (Chrome) pour l'application AMI. Les scénarios couvrent les parcours utilisateurs complets : authentification FranceConnect, notifications push, démarches, etc.
Stack : WebdriverIO v9 + Appium 3 + TypeScript + Testing Library
| Outil | Installation |
|---|---|
| Node.js ≥ 20 | nodejs.org |
just |
brew install just |
Android SDK + adb |
Android Studio → SDK Manager |
Xcode + xcodegen |
App Store + brew install xcodegen |
| Appium (global) | npm i -g appium |
Simulateur iOS attendu : iPhone 17 Pro (ou définir IOS_SIMULATOR dans .env.local)
Émulateur Android : AVD de type Pixel, API 36 — nom configurable via ANDROID_DEVICE_NAME dans .env.local
cp .env .env.local # puis remplir AMI_ENV et les variables NOTIF_*
just setup # npm install + drivers Appium, may not work on non mac os
just check # vérifier que les outils sont présentsHors CI, .env.local est obligatoire (garde-fou _require-dotenv dans le justfile) — en CI, les
variables viennent du workflow GitHub Actions. Pour les comptes de test FranceConnect, copier
src/helpers/test-users.local.example.ts en src/helpers/test-users.local.ts (non commité, comme .env.local).
just test-android # tous les tests Android
just test-ios # tous les tests iOS
just test-webapp # tests webapp, Chrome visible
just test-webci # tests webapp, headless (mode CI)
just test-android "src/tests/mobile/notifications*" # un ou plusieurs fichiers (glob)
just test-android-suite CI # suite nommée (test-suites.ts) — idem test-ios-suite / test-webapp-suite / test-webci-suite
just check-code # lint + typecheck avant commit
just open-report # rapport Allure du dernier run
just clean-install # réinstallation propre (rm node_modules + npm ci)
just upgrade # met à jour les dépendances (npm-check-updates)
just push-notification <login> [titre] # publie une notification de test via l'APIToutes les commandes passent par
just. Ne jamais appeler directementnpm,npx,adb,xcrunouappium.
wdio.base.conf.ts config partagée (timeouts, reporters Allure, hooks)
wdio.android.conf.ts capabilities Android + service Appium port 4723
wdio.ios.conf.ts capabilities iOS + service Appium port 4724
wdio.webapp.conf.ts capabilities Chrome (headless ou visible), pas de service Appium
test-suites.ts suites nommées (WDIO_SUITE) + resolveSpecs()
src/
driver/
capabilities.ts androidCapabilities / iosCapabilities
platform/
index.ts platform() : PlatformAdapter — dispatch android/ios/webapp
helpers/
webview.ts tl(), retourJusquATexteVisible()
notifications-api.ts publishNotification() avec retry 5xx
pages/
*.page.ts Page Objects — actions métier, sans sélecteurs
locators/
*.locators.ts sélecteurs par plateforme + getXxxLocators()
scripts/
*.ts scripts CLI lancés via just (inspect-webview, push-notification)
tests/
mobile/*.test.ts scénarios Mocha Android + iOS
webapp/*.test.ts scénarios Mocha webapp
docs/
adr/ décisions d'architecture (ADR)
Les tests s'appuient sur deux couches : les Page Objects (src/pages/*.page.ts, actions
métier sans sélecteurs directs) et des requêtes sémantiques qui trouvent les éléments comme
un utilisateur les perçoit (rôle ARIA, texte visible, accessibility id en natif).
test (scénario)
└── Page Object ("ouvrir l'inbox")
└── tl().getByRole / findByText — élément par rôle ARIA ou texte visible
Le détail des conventions (POM 3 niveaux, tl() vs $()/$$() vs driver.execute(), WebView
et contextes) est dans CONTRIBUTING.md — à lire avant d'écrire un test. Le
raisonnement complet derrière la règle de sélection (tableaux type de page × action) est archivé
dans l'ADR
docs/adr/2026-07-09-Strategie-de-selection-des-elements.md.
Un workflow réutilisable orchestre les suites de tests par plateforme (Android, iOS, webapp), déclenché depuis les dépôts frères (backend, apps mobiles) sur pull request. Les résultats Allure de chaque plateforme sont fusionnés en un rapport unique, commenté sur la PR d'origine.
Ce que la CI lance correspond exactement aux suites nommées de test-suites.ts (just test-android-suite, test-ios-suite, test-webapp-suite, test-webci-suite) — reproduire
localement un run CI consiste à lancer la suite du même nom. Détail des workflows et décision
d'architecture : docs/adr/2026-08-04-Integration-continue-Github-Actions.md.
Les variables AMI_ENV (environnement backend ciblé) et NOTIF_* (clés API notifications) sont
dans .env.local à la racine — non commité. Voir .env pour les noms des variables à renseigner.
- Inspecter l'écran avec
just inspect - Créer ou compléter les locators dans
src/pages/locators/ - Créer ou compléter le Page Object dans
src/pages/ - Écrire le scénario dans
src/tests/mobile/ousrc/tests/webapp/selon la cible - Valider :
just check-codepuisjust test-android "MonTest"
Les règles générales (Page Objects, sélection des éléments, WebView, assertions, isolation, retry, Allure, débogage) sont toutes dans CONTRIBUTING.md. Les cas particuliers (un seul écran, une seule méthode) sont documentés en commentaire directement dans le fichier de code concerné plutôt que dans un fichier séparé.
Le raisonnement détaillé (tableaux page × action) derrière la règle de sélection résumée dans
CONTRIBUTING.md §2 est archivé dans l'ADR
docs/adr/2026-07-09-Strategie-de-selection-des-elements.md.
Les apps hybrides ont deux arbres d'éléments distincts (natif XCUITest/UIAutomator2 et DOM web) : sans observation directe, impossible de savoir dans quel contexte on est ni quelle est la structure réelle. Les règles de fond (ne jamais commiter un locator non validé, etc.) sont dans CONTRIBUTING.md.
- Inspecter l'écran avant d'écrire un sélecteur :
La cible auto-détecte la plateforme via le seul appareil connecté (émulateur Android ou simulateur iOS déjà démarré).
just inspect # liste les éléments interactifs de la WebView courante - Tester un sélecteur sur un scénario isolé plutôt que sur tout le fichier :
just test-android "src/tests/mobile/notifications.test.ts" - Consigner uniquement ce qui a été vérifié : commiter avec un message qui explique le pourquoi (bug WKRDP, AX tree périmé, etc.), pas juste le sélecteur qui « devrait marcher ».
Avant toute session de débogage, regarder le dernier rapport Allure (just open-report,
screenshots au moment de l'échec) et .wdio-logs/appium-android.log / appium-ios.log.
Le cycle « modifier un locator → relancer just test-android » coûte ~60 s (boot émulateur,
install, login FranceConnect, navigation) ; trouver le bon sélecteur prend souvent 3 à 5 cycles.
browser.debug() suspend le test en cours et ouvre un REPL Node dans la session Appium vivante :
browser, driver, $, $$ sont disponibles, plus des helpers projet (listInteractive,
listInteractiveAll, inWebContext, webViewInfo, refreshAxTree, getContexts,
saveScreenshot). Taper help() dans le REPL pour la liste à jour.
# App déjà buildée et installée, émulateur/simulateur démarré
just build-android && just start-android # ou build-ios / start-ios
export WDIO_DEBUG=1 # désactive le timeout Mocha (2 min par défaut) — sans ça le REPL se fait tuer// Dans src/tests/, test scratch qui navigue jusqu'à l'écran à explorer puis se suspend
it('debug — explorer la page notifications', async () => {
await authenticate()
await NotificationsInboxPage.openFromHome()
await browser.debug() // ← suspend ici, le REPL s'ouvre dans le terminal
})WDIO_DEBUG=1 just test-android "debug — explorer"Dans le REPL :
> help() // liste des helpers disponibles
> await getContexts() // ['NATIVE_APP', 'WEBVIEW_fr.gouv.ami.staging']
> await listInteractive() // éléments natifs du contexte courant
> await listInteractiveAll() // natif puis webview en un seul appel
> await inWebContext(async () => await listInteractive()) // éléments de la WebView
> await webViewInfo() // { url, visible: 'visible'|'hidden', title }
> await $('~Notifications').click() // tester un locator natif
> await inWebContext(async () => { // tester un locator WebView
const el = await tl().findByRole('link', { name: /Notifications/i })
await el.click()
})
> await saveScreenshot('inbox-empty') // → /tmp/inbox-empty.png
> .exit // ou Ctrl-C deux foisRecopier les locators validés dans src/pages/locators/*.locators.ts — jamais un locator non
testé dans le REPL ou en run complet.
Autres outils utiles : chrome://inspect/#devices dans Chrome pendant une session
browser.debug() inspecte visuellement la WebView Android. Appium Inspector (app desktop),
connecté sur localhost:4724, inspecte le contexte natif iOS. logLevel: 'debug' dans
wdio.base.conf.ts affiche chaque commande Appium — à ne pas commiter. wdio repl (CLI
standalone) est déconseillé pour AMI : il faudrait redéclarer toutes les capabilities à la main, et
l'app ne serait pas dans son état post-login — toujours préférer browser.debug() dans un test scratch.
Sur iOS, ne jamais appeler driver.switchContext('NATIVE_APP') au milieu du flow FranceConnect —
voir CONTRIBUTING.md §4. Si listInteractive() retourne
une liste vide en WebView alors que la page est visuellement rendue (AX tree iOS périmé après un
redirect), appeler await refreshAxTree() puis relister.
Pendant un run just test-webapp (Chrome visible), ne pas ouvrir les DevTools ni poser de
breakpoint sur l'onglet testé — la commande WebDriver en cours bloque jusqu'au timeout de garde
(ENSURE_APP_WINDOW_TIMEOUT_MS, 20 s, dans src/platform/browser.adapter.ts). Utiliser
console.log + just test-webci (headless) pour un diagnostic sans interaction manuelle sur l'onglet.
- écrans de toute première connexion (après suppression des données via la cli scalingo)
- Paramétrer les zones scolaires et constater l'ajout et suppression d'éléments dans le calendrier (on les enlève tous, le calendrier est vide, on en remet un, ce n'est pas vide (autour de Noël, on remet toutes les zones d'origine))
- Sur android constater le fonctionnement des notifications push native (login en refusant, notif envoyée, on les accepte, notif envoyée et vue en push)
- Agenda : élections et auto-promo OTV, ... c'est fluctuant selon les dates, a tester en auto ?
- Teste de démarche utilisant OTV
- le reste du cahier de recettes