leonard_native 0.2.2
leonard_native: ^0.2.2 copied to clipboard
A pure-Dart Leonard contract extension that perceives and drives a native mobile app over the OS accessibility tree (via Appium/XCUITest): a stateful, self-watching extension projecting the a11y tree [...]
0.2.2 #
-
Behaviour change — Chrome credential sheets auto-recover:
enter_textnow detects a positively identified Chrome bottom sheet after an obstructed write, dismisses it, re-resolves the invalidated element handle, and retries once. Remove consumer-owned Touch-To-Fill dismissal logic: it is redundant. Any transitional consumer dismissal must remain positively gated because a second bare Androidbacknavigates the Custom Tab away. If detection or dismissal fails, the existing cause-bearing error remains the final result. The detection probe itself fails safe toward NOT acting: an unreadable or malformed/sourcereads as "nothing obstructing", so an obstructed write still falls through to the pre-existing click +mobile: typefallback rather than aborting on a transient read. -
Fix (destructive):
UiAutomator2Backend's keyboard dismiss no longer fires a barePOST /back. It now probesappium/device/is_keyboard_shownfirst and presses nothing when no soft keyboard is up.backis Android's dismiss gesture only while a keyboard holds focus; with none up it is plain navigation, and sincesetValue/mobile: typedo not raise the soft keyboard, the old unconditional press navigated a Chrome Custom Tab AWAY at the end of every successfulenterText— stranding the flow, because later field lookups then 404 against a page that is no longer showing. If the keyboard state cannot be read, nothing is pressed: a keyboard left up is recoverable, a spurious back is not. This brings Android in line with the iOS impl, which already probed for aDonekey before clicking. -
NativeNodegainsresourceId, the Androidresource-id(null on iOS, where XCUITest has no analogue — itsidentifieris already carried bya11yId). It is the only stable, non-localising way for a Dart consumer to identify a platform overlay: Chrome's Touch-To-Fill sheet is matched bytouch_to_fill_sheet_title/bottom_sheet, while its title text, content-desc and per-row summary all localise, so string matching breaks on a non-English device. Deliberately NOT added totoRecord(): that record is the canonical cross-host schema and stays byte-identical toleonard_flutter's semantics fragment, which has no resource-id to emit. The model addresses nodes byidentifier/label, so the wire shape is unchanged and no snapshot expectations move. -
Fix:
UiAutomator2Backend.enterTextnow types into Chrome web-content inputs. UiAutomator2 implementsPOST /element/{id}/valueasAccessibilityNodeInfo.performAction(ACTION_SET_TEXT), which Chrome's web<input>nodes refuse withinvalid element state— so any consumer driving an OAuth/Auth0 login through a Chrome Custom Tab was blocked at the first text field. On that errorenterTextfalls back toclick+mobile: type, which injects key events. (/keysis NOT usable as the fallback: for arbitrary text it shares the same ACTION_SET_TEXT handler and fails identically.) -
The fallback verifies
attribute/focusedafter its click and throws with the cause named rather than typing into the void.mobile: typereports HTTP 200 even when the element cannot receive input, and for a MASKED field an empty readback is indistinguishable from a correct write, so an obstructed field would otherwise surface as a silently empty password. The known obstruction is Chrome's Touch-To-Fill sheet, which both refusesACTION_SET_TEXTand swallows injected keystrokes — while it is up, NO write path succeeds, so the sheet must be dismissed beforeenterTextcan work at all. -
Behaviour change, relevant if you have failure-triggered recovery: an
enterTextthat previously FAILED on a Chrome web input now succeeds, so recovery paths keyed on that failure will stop firing. Specifically, the click that focuses the field can raise Chrome's Touch-To-Fill "Use saved password?" sheet, and because the write now succeeds that sheet can survive into the next step and obscure a following submit tap. Dismiss it on its own signal rather than on anenterTexterror. -
NativeExceptiongains an optionalcodecarrying the W3C WebDriver error code (invalid element state,no such element, ...) when the failure came from a remote error body;nullfor transport and decode failures. Both backends populate it.messageis unchanged and still carries the code as a prefix, so anything reading the message is unaffected.
0.2.0 #
- Breaking: the iOS
AppiumBackendpublic API is renamed toXcuiTestBackend, and itsplatform:constructor parameter is removed. - Migration: replace
AppiumBackend(..., platform: 'ios')withXcuiTestBackend(...). - Breaking: VM-service methods now use the unified
ext.leonard.*namespace supplied byleonard_contract.
0.1.2 #
- Android support:
UiAutomator2Backenddrives a native Android app over a local Appium server running the UiAutomator2 driver — the additive sibling of the iOSAppiumBackend. It shares the generic W3C transport (session, element find, the 4-tier resolve chain, pointer-action tap/swipe) and keeps every Android divergence inside the impl: a<hierarchy>/sourceparser, content-desc as the tier-1 identifier, resource-id-or-positional xpath synthesis, attribute/password-derived masking with attribute/text readback, and a press vocabulary wherebackis recognized and the iOS-only alert keys throw. - New
backendForPlatform(...)— the one place that maps a platform string to aNativeBackend, so the wiring is testable without a device. An unrecognized platform throws rather than silently falling back to iOS (which would parse an Android tree with the XCUITest parser and observe nothing). bin/leonard_native_host.dartselects throughbackendForPlatform, so--platform androidnow works; an unsupported platform is an exit-64 usage error rather than an uncaught throw.
0.1.1 #
- The per-node record now surfaces the OS accessibility identifier under the
canonical
identifierkey — the same stable, locale-proof addressing key as Flutter'sSemantics(identifier:)— for cross-host record parity with the Flutter semantics fragment. Previouslya11yIdwas selector-internal and never wired to the observation.
0.1.0 — initial native host #
- Initial
leonard_nativepackage:NativeExtension(a stateful, self-watchingLeonardExtension) projects the OS accessibility tree into a genesis_perception fragment and exposestap/enter_text/press/swipetools. - The
NativeBackendseam keeps all device I/O behind a synchronousbuildPerception().AppiumBackenddrives a local Appium server over W3C WebDriver against an iOS simulator (XCUITest);FakeNativeBackendis the shipped test impl. - Standalone VM-service host runner at
bin/leonard_native_host.dart.