GUI automation notes (Android wallet)
Canonical notes for graphical Android wallet tests against GOA / stage.
Minimal variant (implemented first) — status 2026-07
This is the minimal vanilla path we actually shipped; full dual-platform
GUI is planned via flags (below), not required to use these scripts today.
| Piece |
Status |
Notes |
| F-Droid published APK install |
done |
net.taler.wallet.fdroid 1.6.1 / 854 |
| Source build + same smoke |
done |
:wallet:assembleFdroidDebug → net.taler.wallet.fdroid.debug |
| Default source branch |
done |
dev/hernani-inference/fix-bank-withdraw-auto-exchange (minimal GOA exchange auto-add) |
| Deep-link entry (≡ QR) |
done |
adb VIEW taler://withdraw/… / taler://pay… |
| Explorer API mint (chain) |
done |
run-goa-gui-chain.sh (GOA + stage) |
| UI taps via uiautomator |
done |
best-effort Confirm/ToS/Pay; ANR → prefer Wait |
| Screenshots / logcat artifacts |
done |
under out*, out-gui-chain/ (gitignored) |
| Host CLI e2e settlement |
separate |
taler-monitoring.sh e2e / ladder (not Android UI) |
| Reliable unattended Confirm on 4 GiB Linux host |
limited |
System UI ANR; use phone or more RAM |
| iOS GUI |
not in this tree |
see taler-ios dev/hernani-inference/gui-workflows |
| macOS full dual AVD helpers |
upstream |
taler-android gui-workflows (Homebrew); ported ideas here for Linux |
Ground rule: bring it to run; app diffs only if needed and minimal; prefer
extending existing dev/hernani-inference/* branches over new trees.
Minimalvariante: was geht / was nicht
Einschränkungen der aktuell implementierten Minimalvariante (deep-link +
uiautomator best-effort). Kein voller Dual-Platform-GUI-Stack, kein Ersatz für
Host-CLI-Settlement.
Geht (grün)
| Fähigkeit |
Wie / Hinweis |
| APK installieren |
F-Droid net.taler.wallet.fdroid oder Source assembleFdroidDebug (.debug) |
| GOA-Exchange ohne manuelles Add |
Source-Build von fix-bank-withdraw-auto-exchange (Default in run-android-build-and-smoke.sh) |
| Withdraw/Pay starten |
adb deep-link taler://withdraw/… / taler://pay… (Ersatz für QR-Scan) |
| Light UI-Drive |
Confirm / Accept / Pay-Taps über Label-Suche (lib_ui.py, gui-smoke, chain) |
| Multi-Runden-Taps |
run-android-gui-smoke.sh / run-goa-gui-chain.sh (best-effort) |
| Explorer-Mint (Kette) |
run-goa-gui-chain.sh + EXP_PW_FILE (GOA + stage) |
| Stack-Wahl |
STACK=goa / stage (Bank/Merchant-URLs) |
| Artefakte |
Screenshots, UI-XML, logcat unter out* / out-gui-chain/ (gitignored) |
| Hybrid-Smoke |
Install + Intent + leichte Taps: run-android-pay-smoke.sh |
| Settlement nachweisen |
Host-seitig: taler-monitoring.sh e2e / ladder (nicht Android-UI) |
| Flags abschalten |
AUTO_ANDROID=0 skip; AUTO_GUI=0 → nur deep-link/pay-smoke |
Geht nicht oder nur eingeschränkt (rot / gelb)
| Beschränkung |
Folge / Workaround |
| Unattended Confirm → settled im Emulator (~4 GiB Host) |
Häufig System UI ANR; Taps bleiben hängen. Prefer Wait auf ANR-Dialog, echtes Gerät, oder Host mit mehr RAM. Kein zuverlässiges grünes E2E nur über GUI auf dem schwachen Emulator. |
| Vollständige Wallet-Settlement-Assertion in der GUI |
Minimalvariante prüft nicht „Balance final / transfer_done“ in der App-Oberfläche. Proof bleibt CLI/e2e. |
| Kamera / physischer QR-Scan |
Absichtlich nicht automatisiert; deep-link ist der Shortcut. Landing-QR-Pfade sind HTTP-Thema, nicht Android-GUI. |
| Browser-Shop-Checkout-UI |
Kein Chromium/WebView-Drive; Pay-URI kommt per Template-POST + Intent. |
| Volles ToS-Scroll / alle Dialoge |
Best-effort Accept-Tap; lange ToS oder unerwartete Sheets können hängen bleiben. |
| Published F-Droid allein auf GOA |
Kann Exchange-Add / Spinner-Probleme zeigen → fix-branch-APK bauen; bei Spinner-Hang optional fix-withdraw-spinner-fallback. |
| iOS-GUI |
Nicht in diesem Tree; siehe taler-ios gui-workflows. |
| macOS dual AVD / Homebrew-Helpers |
Upstream gui-workflows; hier nur Linux-taugliche Port-Ideen. |
AUTO_* in jedem Script erzwungen |
Design + teilweise verdrahtet; Wrapper-Checkliste noch offen. |
run-until-done / CLI-Wallet in GUI-Skripten |
Gehört zu CLI-Automation, nicht GUI; siehe CLI-AUTOMATION-NOTES.md. |
| CI grün = „User hat bezahlt“ |
Smoke = Intent + best-effort UI. Wirtschaftlicher Erfolg = Host-e2e / ladder / Explorer. |
Erwartetes Ergebnis pro Schicht
| Schicht |
Erfolgskriterium Minimalvariante |
| A Install |
APK installed, App startet |
| B Deep-link |
Intent delivered, Wallet öffnet Withdraw/Pay-Flow |
| C GUI taps |
Dump+Tap ohne Crash; ANR ggf. mit Wait; kein Garant für „Paid“ |
| D Evidence |
Artefakte geschrieben |
| Settlement |
Außerhalb GUI: Host e2e/ladder |
Wann Minimalvariante reicht
- Smoke nach APK-/Branch-Build (Intent kommt an, App crasht nicht).
- Manuelle Nacharbeit am Gerät nach vorbereiteten URIs.
- GOA/stage Erreichbarkeit von Landing/Template + Wallet-Einstieg.
Wann nicht reicht → nächster Schritt
- Unattended grünes Pay-E2E auf dem Emulator → mehr RAM / physisches Gerät, ggf.
fix-withdraw-spinner-fallback.
- Beweis „Münzen da / Merchant paid“ → CLI e2e/ladder, nicht GUI-smoke.
- iOS / Dual-Platform → andere Repos/Flags, nicht diese Skripte.
cd scripts/taler-monitoring/android-test
# Minimal hybrid (install + deep-link + light taps)
STACK=goa ./run-android-pay-smoke.sh
# GUI multi-round taps
STACK=goa ./run-android-gui-smoke.sh
STACK=stage ./run-android-gui-smoke.sh
# Explorer mint + multi withdraw/pay chain (from gui-workflows)
EXP_PW_FILE=$HOME/src/koopa/koopa-admin-secrets/koopa/host-root/taler-bank/bank-explorer-password.txt \
STACK=goa PKG=net.taler.wallet.fdroid.debug \
./run-goa-gui-chain.sh
# Build fix-branch APK then smoke (GUI=1 for gui smoke)
./run-android-build-and-smoke.sh
GUI=1 ./run-android-build-and-smoke.sh
Platform capability flags (planned + defaults)
Automation can run on hosts that support Android only, GUI tooling only
(conceptual), or both. Flags keep that explicit for CI and laptops.
Proposed env flags
| Variable |
Values |
Meaning |
AUTO_ANDROID |
0 / 1 |
Run Android wallet automation (adb, APK, emulator/device) |
AUTO_GUI |
0 / 1 |
Drive graphical UI (uiautomator taps, multi-round). If 0, deep-link/CLI-only install smoke. |
AUTO_PLATFORM |
auto / linux / macos / ios |
Host family (optional override) |
EMULATOR_HEADLESS |
1 (default) / 0 |
No host window (-no-window). Server/CI-safe. |
WINDOWED |
0 / 1 |
Shortcut: WINDOWED=1 ⇒ show emulator window (EMULATOR_HEADLESS=0) |
EMULATOR_GPU |
default swiftshader_indirect |
Guest GLES still runs headless (layout/taps/screenshots). Override host only if windowed + real GPU. |
AUTO_START_EMULATOR |
1 (default) / 0 |
If no adb device, start AVD via start-android-emulator.sh --wait |
Headless mode (default)
Default for all GUI / pay smokes: no window on the host. Opening an emulator
GUI on servers (or headless CI) is wrong; these scripts therefore start the AVD
with -no-window and still keep graphics logic in the guest:
| Piece |
Headless default |
| Host window |
off (-no-window, QT_QPA_PLATFORM=offscreen, no DISPLAY) |
| Guest GLES |
on via SwiftShader (-gpu swiftshader_indirect) |
| UI automation |
on — uiautomator dump/tap + screencap (no X11 needed) |
| Audio / boot anim |
off (-no-audio -no-boot-anim) |
# explicit (same as default)
./start-android-emulator.sh --wait
# or let smoke auto-start headless AVD when no phone is plugged in
STACK=goa ./run-android-gui-smoke.sh
# laptop: show the emulator window
WINDOWED=1 ./start-android-emulator.sh --wait
# or: EMULATOR_HEADLESS=0 EMULATOR_GPU=host ./start-android-emulator.sh --wait
Shared code: lib_android_env.sh + start-android-emulator.sh.
Semantics:
AUTO_ANDROID |
AUTO_GUI |
Behaviour |
1 |
0 |
Android install + deep-link smoke only (no multi-round taps) |
1 |
1 |
Android + graphical drive (vanilla GUI / chain) |
0 |
1 |
Reserved (e.g. future desktop/web GUI); currently no-op with a clear message |
0 |
0 |
Skip mobile automation |
Defaults by host (when flags unset)
Host (uname -s) |
Default AUTO_ANDROID |
Default AUTO_GUI |
Rationale |
| Linux |
1 |
1 if device/emulator present, else scripts exit 3 |
This repo’s day-to-day path; Android only (no iOS here) |
| Darwin (macOS) |
1 |
1 |
Can run Android emulators and (separately) taler-ios GUI helpers; both flags on for Android scripts; iOS is out of tree |
| Other |
0 |
0 |
Fail closed |
Linux default = Android (no second mobile platform in this suite).
macOS may enable both ecosystems in the wider monorepo sense; for these
scripts only Android is implemented — set AUTO_ANDROID=1 (default) and keep
iOS under taler-ios.
Resolution helper (convention for future wrappers)
# Example for a future run-all-mobile.sh
os=$(uname -s)
: "${AUTO_PLATFORM:=auto}"
case "$AUTO_PLATFORM" in
auto) case "$os" in Linux) AUTO_PLATFORM=linux ;; Darwin) AUTO_PLATFORM=macos ;; *) AUTO_PLATFORM=other ;; esac ;;
esac
case "$AUTO_PLATFORM" in
linux)
: "${AUTO_ANDROID:=1}"
: "${AUTO_GUI:=1}"
# no iOS
;;
macos)
: "${AUTO_ANDROID:=1}"
: "${AUTO_GUI:=1}"
# optional later: AUTO_IOS=1 for taler-ios scripts
;;
*)
: "${AUTO_ANDROID:=0}"
: "${AUTO_GUI:=0}"
;;
esac
Scripts today implement Android only; they should honour:
AUTO_ANDROID=0 → exit 0 with “skipped (AUTO_ANDROID=0)”
AUTO_GUI=0 → call deep-link smoke without multi-round GUI (or set GUI_ROUNDS=0)
Vanilla layers (detail)
| Layer |
What |
Tooling |
| A — Install |
F-Droid or from-source APK |
adb install |
| B — Entry (shortcut) |
taler://withdraw/… / taler://pay… |
adb am start -a VIEW |
| C — Graphical UI |
Confirm / ToS / Pay taps; ANR Wait |
uiautomator + lib_ui.py / chain |
| D — Evidence |
Screenshots, XML, logcat, URIs |
out*/ |
Legitimate shortcuts
| Shortcut |
Replaces |
| Deep-link withdraw/pay |
Camera QR / opening paywall |
Host POST template → pay URI |
Browser shop checkout UI |
| Label-list taps |
Human reading button text |
| Skip full ToS scroll |
Tap Accept if shown |
Scripts
| Script |
Role |
run-android-pay-smoke.sh |
Hybrid: install + deep-link + light taps |
run-android-gui-smoke.sh |
Multi-round GUI drive |
run-goa-gui-chain.sh |
Multi mint/withdraw/pay (gui-workflows port) |
run-android-build-and-smoke.sh |
Build inference fix branch + smoke (GUI=1 optional) |
start-android-emulator.sh |
Start AVD (headless default, SwiftShader) |
lib_android_env.sh |
Flags, PATH, android_ensure_device |
lib_ui.py |
Dump/tap/ANR helpers |
Stacks under test
| Stack |
Withdraw |
Pay |
| GOA |
explorer mint / demo-withdraw.json @ bank.hacktivism.ch |
goa-shop templates / Paivana pay-template |
| stage |
explorer / demo-withdraw @ stage.bank… |
fermes / jardin public templates |
Upstream branches (taler-android dev/hernani-inference/*)
| Branch |
Role |
gui-workflows |
macOS emulator helpers + original goa-chain-emu.sh |
fix/bank-withdraw-auto-exchange |
Minimal GOA exchange auto-add (default build branch) |
fix/withdraw-spinner-fallback |
Spinner + OIM; use if spinner still hangs |
experimental-oim* |
Optional cash UI |
Checklist