fix: rescale gesture coordinates for compatibility-mode window mismatches - #1249
fix: rescale gesture coordinates for compatibility-mode window mismatches#1249mykola-mokhnach wants to merge 3 commits into
Conversation
…ches XCUICoordinate never rescales a raw points offset when an app's own window size differs from the device's (e.g. an iPhone-only app running in iPad compatibility mode - see appium/appium#16185). Tap, force touch, drag, swipe, and scroll gestures anchored via a raw offset from an element could land on the wrong point as a result. Normalize offsets against the target element's own frame instead, via a new shared FBCoordinateWithAnchorOffset() helper, so XCTest resolves them against whatever frame it reports at gesture-synthesis time. Scroll-to-visible additionally now anchors to a live element resolved from the scroll view's snapshot rather than the application, and surfaces failures instead of silently retrying or falling back to the previous unscaled behavior. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G67QwebqZCxEYN6XmJDGJs
|
@Dan-Maor Could you please help verifying it on a real device? |
|
I’m out of the country at the moment, I’ll be back on Tuesday and will be happy to help testing it then. |
FBElementCommands.m calls it from gesture handlers that are compiled for watchOS (excluded only for tvOS), but it was declared/defined under a TARGET_OS_TV && TARGET_OS_WATCH guard, breaking the watchOS build. Only FBAdjustDimensionsForApplication (needs UIInterfaceOrientation) stays excluded from watchOS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G67QwebqZCxEYN6XmJDGJs
This comment was marked as outdated.
This comment was marked as outdated.
…frame element.frame can already be scaled for a compatibility-mode window mismatch, while the incoming points offset is measured in the WDA-reported (wdFrame) coordinate space - dividing by element.frame double-applied the scaling and left element-relative taps/drags landing on the wrong point, exactly as before the original fix. Also replaces the alert-opened check in the window-size-mismatch regression test with an exact landing-position assertion, using the Touch page's touchable view (which now records each touch-down location as its accessibility value) as ground truth - a large target could still catch an incorrectly-scaled tap and pass silently. Addresses #1249 (review comment 5121824304). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G67QwebqZCxEYN6XmJDGJs
|
Thanks for the extra normal-window coverage — that matches the fix pushed in 2169f81 (switched |
|
Let me check with the latest. |
|
Retested exact commit
For the compatibility-mode probe, the W3C offset error fell from 46.75 to 0.13 app points, the element-relative tap error from 132.82 to 0.07, and the drag endpoint error from 121.91 to 0.15. These match the earlier local experiment. Raw viewport error remains 218.91 points, as documented. Native-iPad errors were zero; the iPhone's maximum was 0.71 points from rounding its half-point viewport center to integer x/y. Element-relative iPhone taps/drags were accurate within floating-point precision. I also ran
The first control attempt failed on a post-gesture touch-view lookup; I repeated it cleanly to confirm the intended coordinate assertion failure. For direct XCTest execution, the generated integration runner needed its already-built Environment: iPad14,8 / iPadOS 26.6.1 / Xcode 26.6 (17F113), and iPhone12,8 / iOS 27.0 / Xcode 27 beta (27A5252f); Appium 3.5.2 / XCUITest driver 12.8.2. WDA was rebuilt from the requested commit for each toolchain and its running build identity checked. Both findings from my earlier review are addressed by this commit in these tests. Coverage is still portrait-only for the listed gestures; landscape, force touch, picker wheels, the historical banking app, and the full repository suite were not tested. |
|
Additional device coverage for
One observation from the initial compatibility run: a native center-click command returned without error but did not increment the probe's touch count. The old coordinates were still present, so I counted it as an unrecorded touch, not a misplaced one. Twelve targeted native-click repetitions then passed with immediate measurements, and a fresh-session repeat of the full coordinate sequence also passed all 13 center/element-relative checks. The initial event remains unexplained and is retained as an intermittent observation; I have not attributed it to the PR. Same probe and 2-app-point tolerance as before, using Xcode 26.6 (17F113), Appium 3.5.2 / XCUITest driver 12.8.2. WDA was rebuilt for this device from the exact commit and its running identity checked. These were portrait probe tests; the stock XCTest regression was not rerun on the mini. |
|
Follow-up on
The compatibility app retained a 375 × 667 portrait UIKit layout on the landscape device. WDA reported its window as 667 × 375 and SpringBoard as 1133 × 744. This distinction matters: the test covers that actual window/orientation mismatch. The unsupported viewport tap recorded no new touch; its stored coordinates remained from the previous drag, so they should not be interpreted as a measured viewport miss distance. For the scroll failure, the native table rect was mobile('scroll', {'elementId': table, 'direction': 'down', 'distance': 0.5})
mobile('scroll', {'elementId': table, 'name': 'probe-row-60'})XCTest logged these normalized table gestures: Both start outside the table. The native run ended in the app switcher; its row-60 command reported As a control, direct W3C element-relative drags scrolled the same table in both modes: compatibility content Y 0 → 198.5; native full-screen 364 → 730.5. The native control's nonzero starting offset came from an earlier drag while the reinstalled app was temporarily windowed; it was maximized and its 1133 × 744 geometry verified before the full-screen control. The leading explanation is a coordinate-space mismatch between These are results on the requested PR commit, using the same signed WDA/probe artifacts as the earlier mini portrait run (Appium 3.5.2, XCUITest driver 12.8.2, Xcode 26.6). Portrait scrolling passed previously. A base-revision landscape comparison has not been run, so I am reporting a failure on this head without claiming it is proven to be newly introduced. The element-offset fix remains effective in this landscape setup; the scroll path needs further investigation. |
|
Thanks for tracking this down. The |
|
Yeah, all of my tests in both orientation had good results. lgtm overall |
Summary
Fixes appium/appium#16185: taps/gestures can land on the wrong point when an app's own window size doesn't match the device's (e.g. an iPhone-only app running in iPad compatibility mode, or any other compatibility-scaled window).
Root cause
XCUIAutomation.framework:XCUICoordinatebuilt from an element/app origin plus a raw points offset (coordinateWithOffset:) is never rescaled by XCTest — the offset is added as-is and handed straight to event synthesis. The only place XCTest does correct for a mismatched window is when resolving a normalized offset (coordinateWithNormalizedOffset:), which is recomputed against the element's live frame at synthesis time. That's also why[element tap](used by WDA's plain/click) already worked correctly — it resolves via the AX-server-computedactivationPoint, not client-side math — whiletouch/perform, W3C actions, force touch, drag, and scroll (which all built raw offsets from a WDA-reported rect) did not.Fix
Normalize every gesture offset against the target element's own frame before building the coordinate, via a new shared
FBCoordinateWithAnchorOffset()helper (FBMathUtils), instead of composing a raw points offset. Applied to tap/touch/W3C actions, force touch, drag/swipe, and scroll (incl. scroll-to-visible, which now anchors to a live-resolved element rather than the application and surfaces failures instead of silently retrying with an unscaled coordinate).One case is intentionally left as a documented, self-verifying limitation: an element-less absolute offset (e.g. a raw viewport
x,ywith no target element) has no frame to normalize against and XCTest has no mechanism to correct it — covered by a test wrapped inXCTExpectFailurethat will start failing loudly if XCTest ever fixes this itself.