Skip to content

feat: native Android (Kotlin/Compose) twin for native-verb testing - #4

Open
pbertsch wants to merge 1 commit into
mainfrom
feat/android-native-twin
Open

pbertsch wants to merge 1 commit into
mainfrom
feat/android-native-twin

Conversation

@pbertsch

Copy link
Copy Markdown
Member

Summary

Adds a full native Android app at native/android-kotlin/ — a Kotlin + Jetpack Compose twin of the Flutter test app (mobile/) — so flutter-probe's native verb family (tap native, type native, see native, don't see native) has a real non-Flutter app with meaningful state to drive and assert on. Plus a 12-scenario native-verb ProbeScript suite in native/android-kotlin/probe-tests/ and a README section.

  • applicationId com.alphawavesystems.probe_test_app_native (installs alongside the Flutter app)
  • Every interactive/assertable view carries a Compose testTag mirroring the Flutter app's ValueKey names 1:1, surfaced as uiautomator resource-ids via testTagsAsResourceId — verified on-device that probe's FindNativeElement matching (case-insensitive substring over text/resource-id) resolves them
  • Real logic parity, not UI stubs: activity-scoped ViewModels twin the Flutter Providers (same credentials test@test.com/password + admin@test.com/admin123, same error strings, 50-item searchable list with swipe-delete, same settings defaults, same status texts everywhere)

Screen-by-screen parity

Screen Parity Notes
Home (3-tab shell) Full All 11 nav tiles fit on-screen without scrolling (needed: no scroll native verb exists)
Login Full 1s simulated auth, same credentials/errors, loading state
Biometric Login Full Real BiometricPrompt (fingerprint). Single-shot like the Flutter twin: first no-match cancels the OS dialog and shows the Authentication failed banner. Verified end-to-end on emulator with adb emu finger touch 1 / 9999 — the exact commands biometric match / biometric no match issue
Dashboard Full Welcome banner reflects auth state (Welcome, Test User / Biometric User / Guest), stat cards, 10 items, refresh/logout
Settings Full Switches, checkbox, language dropdown, save snackbar, disabled delete, build info
Items Full 50 items, live search, swipe-to-dismiss delete, empty state, FAB
Gestures Full + addition Real drag&drop (bounds-overlap), double-tap, long-press context menu, swipe card. Addition: a tap_capture_area/tap_capture_count single-tap zone (native-only) because the native verb family has no double-tap/long-press/swipe/drag equivalents — this gives tap native a real gesture target. Named tap_capture_* (not tap_*) since native matching is substring-based and tap_area would collide with double_tap_area. Worth backporting to the Flutter page for full 1:1
API Demo Full Same simulated latencies, users list, post result
Device Full Simulated camera/location grants (mirrors the Flutter twin, which also fakes them), real browser intent, real clipboard read
Visual Full Header, 2x2 color grid, counter, image placeholder, typography sample
Dynamic Full Random A/B banner, 10s countdown, 2s fade-in, error dialog, tap counter
Signal Demo Deviation Always uses the Flutter twin's non-probe path (1s async then same status texts). The awaitSignal/deliver signal mechanism lives in the Dart ProbeAgent and has no native counterpart

Deliberate deviations (all documented in code comments)

  1. back_button testTag on every sub-screen's top-bar back arrow — no native go back verb, suites need a tap target to return home.
  2. tap_capture_area/tap_capture_count on Gestures (see table).
  3. Signal screen uses the real-implementation path (see table).
  4. see native finding: double-tap/long-press/swipe/drag and scroll have no native-verb equivalents — those Gestures elements are presence-asserted only in the native suite. Possible future flutter-probe verbs (swipe native, long press native, scroll native).

Verification done

  • ./gradlew assembleDebug passes (JDK 21, AGP 8.11.1, Kotlin 2.2.20, Compose BOM 2025.06.01)
  • Installed on a clean throwaway emulator (both shared emulators were busy with parallel test runs) and walked every screen via uiautomator: all ~80 suite-referenced ids/texts resolved (0 misses), including snackbars, dialog open/close, search filtering (Item 49 shown, Item 12 absent), login success/error, logout
  • Biometric: enrolled fingerprint ID 1, then verified prompt -> no-match -> error banner -> retry -> match -> Dashboard -> logout

Test plan

  • Debug build passes
  • APK installs and launches on emulator
  • All resource-ids resolve through uiautomator (probe's matching algorithm replicated in the verification script)
  • Biometric match/no-match verified with the adb commands probe's verbs use
  • Run probe-tests/native_twin_suite.probe through the probe CLI with a ProbeAgent host connected (needs a free emulator with fingerprint enrolled)
  • Cross-check the id table against the iOS twin being built in parallel

🤖 Generated with Claude Code

https://claude.ai/code/session_01R8STRkxzYNXcJCb5kdyJ7E

Full 12-screen replica (home shell + 11 routes) at native/android-kotlin,
applicationId com.alphawavesystems.probe_test_app_native, built to give
flutter-probe's native verb family (tap/type/see/don't see native) a real
non-Flutter app to exercise:

- Compose testTags mirror the Flutter app's ValueKey names 1:1 and are
  surfaced as uiautomator resource-ids via testTagsAsResourceId
- Real behavior parity: simulated auth (same credentials/errors), 50-item
  searchable list with swipe-delete, gesture zones, settings state,
  countdown/fade/dialog dynamics, API demo, signal statuses
- Real BiometricPrompt (fingerprint) on the biometric screen, driven by
  probe's biometric match / no match verbs (adb emu finger touch)
- probe-tests/native_twin_suite.probe: 12 native-verb scenarios covering
  navigation, login, item search/add, gestures, device, visual, dynamic,
  signal, api, settings, and the biometric flow
- README: new Native Android Twin section
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant