fix(mobile): React Native controls read right on iOS, closeApp closes the app, a lost session is APP_NOT_OPEN, a discovered emulator boots by serial

Merged
OK
1mo ago
+535-78

The first iOS run of the mobile benchmark gates' suites (#498, stacked on this) found the first four; its Android job found the fifth. Landing these first is what lets that gate go green on merge.

  • A view with accessibilityRole="checkbox" or "radio" has no UIKit trait, so React Native spells role and state into the accessibility value (checkbox, unchecked, radio button, checked) and XCTest reports an Other. The node takes the spelled role, checked and expanded from the state words, and keeps only what follows as its value, so getByRole('checkbox'), check(), uncheck(), and toBeChecked work on a React Native checkbox or radio.
  • getByLabel answers with the innermost match, as getByText does: iOS reports a React Native TextInput as a labelled host view around the labelled field, which made every label query on a field LOCATOR_AMBIGUOUS. A field whose text is also its label keeps its value; only Android's echo of a text view's label as its value is dropped.
  • doubleTap() sends two presses instead of agent-device's double-tap gesture, which reaches a React Native Pressable on iOS as one press.
  • device.closeApp() terminates the app before ending the session, so the next openApp starts it fresh, and foregroundApp() after it is APP_NOT_OPEN rather than ENGINE_FAILURE. back(), home(), alert(), dismissKeyboard(), and setOrientation() count as actions for the transition budget, as a tap does.
  • A discovered Android emulator boots by its adb serial. The pool bound a discovered device by the id agent-device lists it under and selected it through the name field; a simulator UDID was inferred as an id, an adb serial was not, so the Android job failed its boot with No device named emulator-5554. SlotBinding.deviceId now travels beside device, deviceSelection puts an id under the platform's field (udid or serial), and a configured device that reads as an emulator serial goes by serial too.
  • The fixture engine maps its errors through the runner's engine error table, so a fixture that throws INVALID_STATE reads as APP_NOT_OPEN.

Unit tests: 142 in the mobile package, including serial selection for a discovered emulator, a configured serial, and a configured name; 39 in the runner's fixture runtime. The device suites that exercise every fix ran on an iPhone 17 Pro simulator against this engine code: 6 files, 50 passed, 10 skipped where agent-device or React Native has no answer yet, each skip naming why. #498 makes that run a gate. Docs: the mobile guide's troubleshooting section, the device option in the mobile reference, the engine reference. Changesets: @e2edev/mobile patch, e2e patch.


Devin Review