Skip to content

Commit 16df132

Browse files
committed
feat: Flutter twin of the native-verb fixture apps
Same 8-element surface as native-test-apps/android and native-test-apps/ios, exercised through probe's normal Dart-agent verbs (this app is its own ProbeAgent host). Every element carries both a Semantics(identifier:) and a matching ValueKey so #id selectors and future native-verb queries resolve to the same widget.
1 parent 3495e11 commit 16df132

70 files changed

Lines changed: 2154 additions & 13 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

native-test-apps/README.md

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,46 @@
11
# Native test apps — purpose-built targets for probe's native UI verbs
22

3-
Two minimal, dependency-free native apps exposing an identical set of stable, test-oriented
4-
elements (a tap counter, a live-echo text field, a toggle, and a hidden-until-revealed message):
5-
6-
| Element | Android resource-id | iOS accessibility id | Visible text |
7-
|---|---|---|---|
8-
| Title | `native_title` | `native_title` | "Native Test App" |
9-
| Counter button | `native_button` | `native_button` | "Tap Me" |
10-
| Counter | `native_counter` | `native_counter` | "Taps: 0" → "Taps: N" |
11-
| Text field | `native_input` | `native_input` | hint "Enter text here" |
12-
| Echo mirror | `native_echo` | `native_echo` | "Echo: (empty)" → "Echo: <typed>" |
13-
| Switch | `native_switch` | `native_switch` | "Native Switch" |
14-
| Reveal button | `native_message_button` | `native_message_button` | "Show Message" |
15-
| Hidden message | `native_message` | `native_message` | "Message Revealed" — absent from the accessibility/uiautomator tree until revealed |
3+
Three minimal apps — one Flutter, two platform-native — exposing an identical set of stable,
4+
test-oriented elements (a tap counter, a live-echo text field, a toggle, and a hidden-until-revealed
5+
message), so the same scenario can be exercised through probe's normal Dart-agent verbs (Flutter)
6+
and its native UI-automation verb family (all three) side by side:
7+
8+
| Element | Flutter Semantics id / ValueKey | Android resource-id | iOS accessibility id | Visible text |
9+
|---|---|---|---|---|
10+
| Title | `native_title` | `native_title` | `native_title` | "Native Test App" |
11+
| Counter button | `native_button` | `native_button` | `native_button` | "Tap Me" |
12+
| Counter | `native_counter` | `native_counter` | `native_counter` | "Taps: 0" → "Taps: N" |
13+
| Text field | `native_input` | `native_input` | `native_input` | hint "Enter text here" |
14+
| Echo mirror | `native_echo` | `native_echo` | `native_echo` | "Echo: (empty)" → "Echo: <typed>" |
15+
| Switch | `native_switch` | `native_switch` | `native_switch` | "Native Switch" |
16+
| Reveal button | `native_message_button` | `native_message_button` | `native_message_button` | "Show Message" |
17+
| Hidden message | `native_message` | `native_message` | `native_message` | "Message Revealed" — absent from the tree until revealed |
18+
19+
## flutter/ — same surface, driven through probe's normal (Dart-agent) verbs
20+
21+
Standard Flutter app, `ProbeAgent.start()` gated behind `--dart-define=PROBE_AGENT=true` (same
22+
pattern as `probe_agent/example`). Every element carries **both** a `Semantics(identifier:)` and a
23+
matching `ValueKey`, so `#id` selectors and (once N-2 lands) native-verb queries resolve to the same
24+
widget. Unlike the two apps below, this app *is* the ProbeAgent host — no separate host app needed,
25+
and `before each test: restart the app` is safe here.
26+
27+
Build: `flutter build apk --debug --dart-define=PROBE_AGENT=true` /
28+
`flutter build ios --debug --simulator --dart-define=PROBE_AGENT=true`.
29+
30+
**Run** (`flutter/probe-tests/flutter_suite.probe`, live-verified 4/5 on emulator-5556 — see the
31+
suite header for a known emulator-side flake on `type into`, not an app defect):
32+
33+
```
34+
adb install -r flutter/build/app/outputs/flutter-apk/app-debug.apk
35+
adb shell am start -n com.alphawavesystems.probe_flutter_fixture/.MainActivity
36+
probe test flutter/probe-tests/ --config flutter/probe-tests/probe.yaml --device <serial>
37+
```
38+
39+
**Real-world pitfall captured here**: `Semantics(identifier:)` wrapping an interactive widget
40+
(here, a `TextField`) doesn't reliably pass the Dart agent's synthetic focus/tap routing through to
41+
the widget underneath — the same class of issue documented for `GestureDetector` taps on physical
42+
devices. Fix: put a matching `ValueKey` directly on the interactive widget itself, not just the
43+
`Semantics` wrapper above it.
1644

1745
## android/ — live target for `tap native` / `see native` / `type native` (N-1)
1846

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"bonsoir_darwin","path":"/Users/patrickbertsch/.pub-cache/hosted/pub.dev/bonsoir_darwin-5.1.3/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"bonsoir_android","path":"/Users/patrickbertsch/.pub-cache/hosted/pub.dev/bonsoir_android-5.1.6/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"bonsoir_darwin","path":"/Users/patrickbertsch/.pub-cache/hosted/pub.dev/bonsoir_darwin-5.1.3/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"bonsoir_linux","path":"/Users/patrickbertsch/.pub-cache/hosted/pub.dev/bonsoir_linux-5.1.3/","native_build":false,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"bonsoir_windows","path":"/Users/patrickbertsch/.pub-cache/hosted/pub.dev/bonsoir_windows-5.1.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[]},"dependencyGraph":[{"name":"bonsoir","dependencies":["bonsoir_android","bonsoir_darwin","bonsoir_windows","bonsoir_linux"]},{"name":"bonsoir_android","dependencies":[]},{"name":"bonsoir_darwin","dependencies":[]},{"name":"bonsoir_linux","dependencies":[]},{"name":"bonsoir_windows","dependencies":[]}],"date_created":"2026-08-16 07:31:20.177497","version":"3.44.8","swift_package_manager_enabled":{"ios":false,"macos":false}}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.dart_tool/
2+
.flutter-plugin-dependencies
3+
build/
4+
android/.gradle/
5+
android/local.properties
6+
android/app/.cxx/
7+
ios/Pods/
8+
ios/.symlinks/
9+
ios/Flutter/Flutter.framework
10+
ios/Flutter/Flutter.podspec
11+
*.iml
12+
.idea/
13+
probe-tests/reports/

native-test-apps/flutter/.metadata

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: "058e0af2c2b57e369d905a03ac9748b0ebf543c6"
8+
channel: "stable"
9+
10+
project_type: app
11+
12+
# Tracks metadata for the flutter migrate command
13+
migration:
14+
platforms:
15+
- platform: root
16+
create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
17+
base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
18+
- platform: android
19+
create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
20+
base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
21+
- platform: ios
22+
create_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
23+
base_revision: 058e0af2c2b57e369d905a03ac9748b0ebf543c6
24+
25+
# User provided section
26+
27+
# List of Local paths (relative to this file) that should be
28+
# ignored by the migrate tool.
29+
#
30+
# Files that are not part of the templates will be ignored by default.
31+
unmanaged_files:
32+
- 'lib/main.dart'
33+
- 'ios/Runner.xcodeproj/project.pbxproj'

native-test-apps/flutter/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# probe_flutter_fixture
2+
3+
Flutter twin of the native fixture apps in `../android` and `../ios` — see the parent
4+
`native-test-apps/README.md` for the shared element table and cross-framework story.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This file configures the analyzer, which statically analyzes Dart code to
2+
# check for errors, warnings, and lints.
3+
#
4+
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5+
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6+
# invoked from the command line by running `flutter analyze`.
7+
8+
# The following line activates a set of recommended lints for Flutter apps,
9+
# packages, and plugins designed to encourage good coding practices.
10+
include: package:flutter_lints/flutter.yaml
11+
12+
linter:
13+
# The lint rules applied to this project can be customized in the
14+
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
15+
# included above or to enable additional rules. A list of all available lints
16+
# and their documentation is published at https://dart.dev/lints.
17+
#
18+
# Instead of disabling a lint rule for the entire project in the
19+
# section below, it can also be suppressed for a single line of code
20+
# or a specific dart file by using the `// ignore: name_of_lint` and
21+
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
22+
# producing the lint.
23+
rules:
24+
# avoid_print: false # Uncomment to disable the `avoid_print` rule
25+
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
26+
27+
# Additional information about this file can be found at
28+
# https://dart.dev/guides/language/analysis-options
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
gradle-wrapper.jar
2+
/.gradle
3+
/captures/
4+
/gradlew
5+
/gradlew.bat
6+
/local.properties
7+
GeneratedPluginRegistrant.java
8+
.cxx/
9+
10+
# Remember to never publicly share your keystore.
11+
# See https://flutter.dev/to/reference-keystore
12+
key.properties
13+
**/*.keystore
14+
**/*.jks
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
plugins {
2+
id("com.android.application")
3+
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
4+
id("dev.flutter.flutter-gradle-plugin")
5+
}
6+
7+
android {
8+
namespace = "com.alphawavesystems.probe_flutter_fixture"
9+
compileSdk = flutter.compileSdkVersion
10+
ndkVersion = flutter.ndkVersion
11+
12+
compileOptions {
13+
sourceCompatibility = JavaVersion.VERSION_17
14+
targetCompatibility = JavaVersion.VERSION_17
15+
}
16+
17+
defaultConfig {
18+
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
19+
applicationId = "com.alphawavesystems.probe_flutter_fixture"
20+
// You can update the following values to match your application needs.
21+
// For more information, see: https://flutter.dev/to/review-gradle-config.
22+
minSdk = flutter.minSdkVersion
23+
targetSdk = flutter.targetSdkVersion
24+
versionCode = flutter.versionCode
25+
versionName = flutter.versionName
26+
}
27+
28+
buildTypes {
29+
release {
30+
// TODO: Add your own signing config for the release build.
31+
// Signing with the debug keys for now, so `flutter run --release` works.
32+
signingConfig = signingConfigs.getByName("debug")
33+
}
34+
}
35+
}
36+
37+
kotlin {
38+
compilerOptions {
39+
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
40+
}
41+
}
42+
43+
flutter {
44+
source = "../.."
45+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
2+
<!-- The INTERNET permission is required for development. Specifically,
3+
the Flutter tool needs it to communicate with the running application
4+
to allow setting breakpoints, to provide hot reload, etc.
5+
-->
6+
<uses-permission android:name="android.permission.INTERNET"/>
7+
</manifest>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
2+
<application
3+
android:label="probe_flutter_fixture"
4+
android:name="${applicationName}"
5+
android:icon="@mipmap/ic_launcher">
6+
<activity
7+
android:name=".MainActivity"
8+
android:exported="true"
9+
android:launchMode="singleTop"
10+
android:taskAffinity=""
11+
android:theme="@style/LaunchTheme"
12+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
13+
android:hardwareAccelerated="true"
14+
android:windowSoftInputMode="adjustResize">
15+
<!-- Specifies an Android theme to apply to this Activity as soon as
16+
the Android process has started. This theme is visible to the user
17+
while the Flutter UI initializes. After that, this theme continues
18+
to determine the Window background behind the Flutter UI. -->
19+
<meta-data
20+
android:name="io.flutter.embedding.android.NormalTheme"
21+
android:resource="@style/NormalTheme"
22+
/>
23+
<intent-filter>
24+
<action android:name="android.intent.action.MAIN"/>
25+
<category android:name="android.intent.category.LAUNCHER"/>
26+
</intent-filter>
27+
</activity>
28+
<!-- Don't delete the meta-data below.
29+
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
30+
<meta-data
31+
android:name="flutterEmbedding"
32+
android:value="2" />
33+
</application>
34+
<!-- Required to query activities that can process text, see:
35+
https://developer.android.com/training/package-visibility and
36+
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
37+
38+
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
39+
<queries>
40+
<intent>
41+
<action android:name="android.intent.action.PROCESS_TEXT"/>
42+
<data android:mimeType="text/plain"/>
43+
</intent>
44+
</queries>
45+
</manifest>

0 commit comments

Comments
 (0)