UITests with SwiftUI Lists Failing to Find Off-Screen Elements in Xcode 14+

Number:rdar://FB11764272 Date Originated:November 7th, 2022
Status:Open Resolved:
Product:XCTest Product Version:Xcode 14+
Classification:Incorrect/Unexpected Behavior Reproducible:Always
## Summary
I have filed feedback for this item, but I am curious whether this is an intended change or if there's a better way to address the behavior change - `FB11764272`.

UITests' XCTest behavior has changed with Xcode 14+ when looking for off-screen elements in a `List` component. 

## The Change
Below is how the behavior worked on the last two major versions of Xcode:
- **Xcode 13:** Off-screen elements are visible to the UITest process and will scroll to those elements for interaction. e.g. calling `tap()` on an off-screen element.
  - This is how UIKit TableViews work, even for cells that haven't been dequeued yet.
- **Xcode 14:** Off-screen elements are NOT visible to the UITest process by default and will cause a test failure if an interaction is attempted. e.g. calling `tap()` on an off-screen element.
  - This change is more in line with how Lazy Stacks worked in SwiftUI for Xcode 13.

The documentation for `XCTUIElement`'s `tap()` method says the following:
> If the element exists within a scrollable view but is offscreen, XCTest will attempt to scroll the element onscreen before performing the tap.

Also, while an old post (7 years ago), this Developer Forums Post thread #16810 has the following response from an Apple Frameworks Engineer:
> You are not supposed to have to scroll manually. Interacting with an element not currently visible in the scroll view is expected to implicitly first scroll the element to be visible without requiring effort. If that's not working for you, please file a bug report (using the Report Bugs link at the bottom of this page). Thanks!

This was true for SwitUI Lists in Xcode 13 but isn't the case with Xcode 14+ (and it appears to continue to not work for Lazy Stacks within ScrollViews in SwiftUI).

## Current Workaround
As my team's entire app is written in SwiftUI and we have an extensive UITest suite, we'll need to find every usage of an interaction API, like `tap()`, and wrap that with a custom method that first scrolls the entire length of the scroll view (at worst) waiting for the intended element to exist.

This involves a lot of work from a development perspective but also adds a lot of time to run through our extensive UITest suite for an already long-running suite.

## Wrap Up
Was this change intentional? If so, what's the suggested way of scrolling to off-screen elements when UI testing a SwiftUI application or is the workaround described above the expected path forward?


Associated Developer Forums Post

Associated Developer Forums Post - https://developer.apple.com/forums/thread/719444

By joshua.shroyer at Nov. 7, 2022, 8:11 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!