Skip to content

feat: native SwiftUI twin of the Flutter test app (11 screens) - #3

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

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

Conversation

@pbertsch

Copy link
Copy Markdown
Member

Summary

Adds native/ios-swift/ — a hand-built SwiftUI app at native/ios-swift/ that replicates all 11 mobile/ screens with real (not stubbed) behavior, for exercising FlutterProbe's native-UI capabilities once iOS bridging lands. Every interactive/assertable view carries an .accessibilityIdentifier that mirrors the Flutter app's ValueKey 1:1, so the same ProbeScript scenarios can eventually target either framework with only the selector syntax changing.

  • Bundle id com.alphawavesystems.probeTestApp.native (distinct from the Flutter app's com.alphawavesystems.probeTestApp — both can coexist on one simulator).
  • Built via xcodegen + xcodebuild -sdk iphonesimulator ... CODE_SIGNING_ALLOWED=NO, same pattern as flutter-probe/native-test-apps/ios/.
  • Biometric Login uses real LocalAuthentication (Face ID/Touch ID) — flutter-probe drives match/no-match outcomes at the Simulator level (xcrun simctl ... notifyutil), independent of the app, so this is compatible with the existing enroll biometric / biometric match / biometric no match verbs.
  • .gitignore follows the sibling fixture's convention — generated .xcodeproj, build/, and Sources/Info.plist are not committed.

Screen-by-screen parity notes

Screen Parity Notes
Home (3-tab shell) Full Custom bottom bar (not system TabView) for full control over tab_*/tab_*_icon identifiers
Login Full 1000ms delay, exact credential pairs, exact error/snackbar text
Biometric Login Deliberate deviation Uses real LAContext always (task requirement), vs. Flutter's PROBE_AGENT-gated RPC branch — see below
Dashboard Full Reachable without auth (Welcome, Guest), exact stat/item text incl. the item_N → Item N+1 index offset
Settings Full No-op save (matches Flutter — no real persistence despite shared_preferences dep)
Items Full Custom drag-based swipe-to-delete (SwipeToDismiss.swift) instead of native two-step swipeActions, to match Flutter Dismissible's single-continuous-swipe gesture shape
Gestures Full .draggable/.dropDestination for drag-and-drop; custom long-press popup (Copy/Delete, no-op) instead of .contextMenu so the long-press-start gesture-count increment fires reliably
API Tests Full All synthetic/hardcoded, matching the Flutter twin (no real HTTP either)
Device Full Permissions are UI-only simulation in both apps; real UIPasteboard for clipboard
Visual Full Deterministic, no animation — built for pixel/visual-regression comparison
Dynamic Full Real 1s countdown timer, 2s fade-in, random A/B banner per mount
Signal Demo Deliberate deviation See below

Deliberate deviations

  1. Biometric: always uses real LocalAuthentication, per the task's explicit instruction — this native app has no probe-agent socket bridge to receive an RPC-delivered bool the way the Flutter app's PROBE_AGENT branch does.
  2. Signal Demo: has no signal-delivery bridge available (native apps have no embedded probe agent yet), so it always takes the same fallback path the Flutter twin uses when PROBE_AGENT is unset — a fixed delay then the happy-path result. deliver signal scenarios are out of scope until such a bridge exists (noted in native_suite.probe, commented out).

N-2 status (iOS native UI bridging)

Still unimplemented. flutter-probe/website/src/content/docs/platform/ios.md ("Native UI Automation" section) confirms tap native/type native/see native are Android-only; iOS support via WebDriverAgent is a written, scoped proposal (docs/proposals/n2-ios-native-ui-bridging.md) not yet implemented. Since ProbeScript's tap/see/wait until verbs against Flutter apps go through an embedded Dart agent package that doesn't exist in this plain-SwiftUI app, no ProbeScript verb can currently drive this app end-to-end — not just the native-specific ones.

native/ios-swift/probe-tests/native_suite.probe records the intended test scenarios (home nav, tabs, login success/failure, biometric match/no-match, dashboard, settings, items, gestures, API, device, visual, dynamic), clearly marked pending at the top of the file, ready to run once N-2 lands.

accessibilityIdentifier ↔ ValueKey table (for Android-twin cross-check)

Identical strings throughout — every Flutter ValueKey('x') maps to SwiftUI .accessibilityIdentifier("x"). Full set (137 identifiers) is enumerated across native/ios-swift/Sources/Screens/*.swift; representative sample:

tab_home, tab_tests, tab_about, welcome_text, version_text, nav_login…nav_dynamic (11 tiles), email_field, password_field, sign_in_button, error_message, sign_in_with_face_id, biometric_error_banner, welcome_banner, stat_card_1..3, item_0..9, logout_button, refresh_button, dark_mode_toggle, notifications_toggle, terms_checkbox, language_dropdown, save_button, search_field, fab_add, list_item_N, dismissible_N, drag_source, drag_target, double_tap_area, long_press_area, swipe_card, gesture_count, request_camera, request_location, request_notifications, gps_display, paste_button, pasted_text, visual_counter, increment_button, countdown, fade_widget, trigger_error, repeat_action, action_count, request_push_permission, start_payment, open_deep_link, signal_status, fetch_users_button, create_post_button, user_0..2, post_result.

Test plan

  • xcodegen generate succeeds
  • xcodebuild -scheme ProbeNativeTwin -sdk iphonesimulator -configuration Debug build CODE_SIGNING_ALLOWED=NO — BUILD SUCCEEDED
  • Installed and launched on booted simulator (iPhone 17 Pro, iOS 26.3); home screen screenshot confirms all 11 tiles + welcome/version text render correctly
  • xcodebuild test — 3/3 XCUITest smoke tests pass, confirming accessibilityIdentifiers actually resolve at runtime (home tiles/tabs, login fields/buttons, dashboard-without-auth)
  • Full native_suite.probe run — blocked on N-2, not yet possible

🤖 Generated with Claude Code

Replicates all 11 mobile/ screens (Home, Login, Biometric, Dashboard,
Settings, Items, Gestures, API, Device, Visual, Dynamic) in plain
SwiftUI with real behavior — same navigation shape, state transitions,
and assertable text as the Flutter app. Every interactive/assertable
view carries an accessibilityIdentifier mirroring the Flutter app's
ValueKey 1:1.

- Bundle id com.alphawavesystems.probeTestApp.native (distinct from
  the Flutter app to avoid simulator collisions).
- Biometric screen uses real LocalAuthentication (Face ID/Touch ID).
- Built via xcodegen + xcodebuild, same pattern as
  flutter-probe/native-test-apps/ios/.
- Verified: xcodebuild build succeeds, app installs and launches on
  simulator, and a standalone XCUITest smoke suite
  (UITests/ProbeNativeTwinUITests.swift) confirms key
  accessibilityIdentifiers resolve at runtime (home, login, dashboard
  screens, 3/3 passing).
- Not yet runnable via ProbeScript end-to-end: iOS N-2 (XCTest/
  WebDriverAgent native UI bridging) is a written, unimplemented
  proposal in flutter-probe. probe-tests/native_suite.probe records
  the intended scenarios, marked pending at the top of the file.
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