Skip to content

scroll reports the requested distance after the scrollable stops moving, and its gesture can end outside the scrollable #2714

Description

@thymikee

What happens

scroll stops moving the scrollable and still reports success with the distance it was asked for. On the SDK 58 fixture's /automation route the content freezes after the first gesture or two, and every later gesture is reported as if it landed:

$ agent-device scroll down 0.75 --session lab
  msg: Scrolled down by 0.75 of the viewport (656px)   gesture 765 -> 109
  automation-press y = 310.7
$ agent-device scroll down 0.75 --session lab
  msg: Scrolled down by 0.75 of the viewport (656px)   gesture 765 -> 109
  automation-press y = not-in-tree
$ agent-device scroll down 0.75 --session lab          # and 5 more, both directions
  msg: Scrolled down by 0.75 of the viewport (656px)   gesture 765 -> 109
  … 5 x "scroll up 0.6" left the identifier list byte-identical

The offsets are read out of snapshot --json (automation-press, automation-alert-result, …). Five consecutive scroll up 0.6 calls returned success: true and left every identifier at the same y, with the app frozen mid-page on a ScrollView that has plenty of content above and below.

This is what turns CI red on test-app/ios27-scene-lifecycle: the smoke scenario scrolls up to four times toward automation-longpress and the screen never moves, so the step asserts id="automation-longpress" did not become visible after scrolling (run 35523907559, job 106112615304).

Geometry

Gesture endpoints are centred on the viewport with a span of amount x viewport height, and are never clamped to the resolved scrollable:

amount gesture viewport
0.5 656 -> 218 402x874
0.6 699 -> 175
0.75 765 -> 109

The /automation scrollable is inset from the window:

ScrollView / role=RCTEnhancedScrollView subrole=UIScrollView rect=(18,178,366,662)

so a 0.75 gesture ends at y=109, which is 69pt above the scrollable's own top edge, in the navigation bar. On /catalog the same build reports rect=(18,62,366,729), every amount stays inside it, and scrolling works in both directions.

Why this stayed hidden is inference rather than measurement, and worth checking before a fix is scoped: main's fixture is the same screen on an older Expo/RN whose scroll view is presumably not inset, so the same unclamped formula would keep landing inside and the missing movement check would never be needed to pass CI. I did not measure main's fixture on this route — its app cannot launch on the 27.x runtimes here.

The success answer is the requested distance, not the observed one

Scrolled down by 0.75 of the viewport (656px) is printed while the measured offset is unchanged. The information needed to catch this is already computed elsewhere: scroll top on the same frozen route refuses honestly —

success=false  "scroll top moved nothing across 3 passes: the container still re…"

— and the CI request log for the failing smoke run shows the post-gesture comparison accepting a snapshot that equals the pre-gesture one:

post_gesture_snapshot_stale_accept   {"action":"scroll","attempts":8,"matchedPreGestureBaseline":true}
post_gesture_snapshot_stabilization_timeout {"action":"scroll","attempts":4,"durationMs":1653}
ios.snapshot-source.acquire          {"error":"iOS Simulator snapshot source unsupported: foreground-owner-unverified"}
ios_snapshot_route_fallback          {"reason":"target-resolution-failed","error":"Unable to resolve the running iOS Simulator app (simulator-target-dis…"}

A directional scroll that observes matchedPreGestureBaseline: true should not be able to answer with a distance.

Environment

  • iPhone 17 simulator, iOS 27.0, also reproduced against the iOS 27.1 CI runner.
  • CLI built from main at 921a2cb3a; no CLI change on the branch — only examples/test-app moves under it (Expo SDK 58 / RN 0.88, whose RCTEnhancedScrollView and inset layouts are what expose the bug).
  • Repro: open com.callstack.agentdevicelab --relaunch --launch-url agent-device-test-app:///automation, wait text "Automation lab", then scroll down 0.75 repeatedly and compare snapshot --json offsets between calls. /catalog is the working control.

Expected

  • scroll answers with observed movement, and fails with a typed reason when the gesture produced none, instead of echoing the requested amount.
  • Gesture endpoints get clamped to the resolved scrollable's frame, so an inset scroll view is still reachable at any amount.

Related: #2711 (interactions on the Duo's inner panel report success and change nothing, with the same absence of display/coordinate evidence in the request log).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions