Skip to content

Conversation

@lechuckcaptain
Copy link
Contributor

@lechuckcaptain lechuckcaptain commented Jan 4, 2026

This PR adds comprehensive SwiftUI support to SBTUITestTunnel with a new example app and enhanced scrolling capabilities for both UIKit and SwiftUI apps.

In order to fully support SwiftUI scrollable views, a new common API scrollContent has been added that automatically detects the view type and works with UITableView, UICollectionView, and UIScrollView.

The following are the three convenience methods added (that they are using the existing scrolling APIs, where is possible):

  • scrollContentWithIdentifier:toElementIndex:animated: for index-based scrolling
  • scrollContentWithIdentifier:toElementWithIdentifier:animated: for element-based scrolling
  • scrollContentWithIdentifier:toOffset:animated: for offset-based scrolling

Note: To improve SwiftUI support for Lazy[H|V][Grid|Stack] components, the scrollContentWithIdentifier:toElementWithIdentifier:animated: function
includes a fallback that scrolls page-by-page and look into the XCUITest accessibility tree, when standard scrolling fails. This logic seems reasonable to me, and it works fine, but I'm open to suggestions 😉

The changes should improve SwiftUI support while maintaining full backward compatibility with existing UIKit implementations.

Note: I configured SwiftUI CI workflow to use the latest macos-26 + Xcode 26.2 to
ensure that SBTUITestTunnel works fine also on more recent setups, while keeping the UIKit CI to macos-15 (macos-latest) + Xcode 16.4.

@lechuckcaptain lechuckcaptain force-pushed the feature/swiftui branch 3 times, most recently from d2cbd08 to 1e2fe04 Compare January 4, 2026 20:33
* Move Example/ to Examples/UIKit/
* Update Podfile paths
* Update .gitignore for new directory structure
This allows SwiftPM-based projects to access SBTProxyURLProtocol,
which is needed for tests that check protocol registration.
@lechuckcaptain lechuckcaptain force-pushed the feature/swiftui branch 2 times, most recently from 01f2066 to 8293f8b Compare January 5, 2026 14:21
@lechuckcaptain lechuckcaptain changed the title Add SwiftUI example Add SwiftUI Example and Enhanced Scrolling API Jan 5, 2026
Add the ability to scroll UIScrollView by one page at a time, by refactoring the existing logic inside commandScrollScrollViewWithIdentifier to a common function that can be called from the scrollScrollViewWithIdentifierByPage.
Add three convenience methods that automatically detect view types:
- scrollContentWithIdentifier:toElementIndex:animated: for index-based scrolling
- scrollContentWithIdentifier:toElementWithIdentifier:animated: for element-based scrolling
- scrollContentWithIdentifier:toOffset:animated: for offset-based scrolling

These methods simplify test code by detecting whether the view is a UITableView,
UICollectionView, or UIScrollView and calling the appropriate specific method.

For SwiftUI compatibility, scrollContentWithIdentifier:toElementWithIdentifier:animated:
includes a fallback that scrolls page-by-page when standard scrolling fails.
@lechuckcaptain lechuckcaptain force-pushed the feature/swiftui branch 5 times, most recently from f9ff6b6 to de1dba3 Compare January 10, 2026 16:48
Refactor build scripts to support both UIKit and SwiftUI examples

Usage:
  Scripts/build_app.rb <project_path> <scheme>
  Scripts/build_uitests.rb <project_path> <scheme>
  Scripts/run_uitests.rb <project_path> <scheme>"
@lechuckcaptain lechuckcaptain marked this pull request as ready for review January 10, 2026 20:23
@tcamin
Copy link
Member

tcamin commented Jan 14, 2026

Would it be possible to have a single source of UITests, currently it seems that tests are duplicated in the UIKit/SwiftUI apps. This would prevent having to remember to copy paste the same implementation twice when adding a new test. wdyt?

@lechuckcaptain
Copy link
Contributor Author

Would it be possible to have a single source of UITests, currently it seems that tests are duplicated in the UIKit/SwiftUI apps. This would prevent having to remember to copy paste the same implementation twice when adding a new test. wdyt?

It makes sense. I thought about it, but in this PR I wanted to limit as much as possible the changes on the current codebase, in order to make it easier to review and limit regressions. Do you think we can do the refactoring on a separate PR or do you prefer if I rework this to add everything in a single PR?

@tcamin
Copy link
Member

tcamin commented Jan 14, 2026

Would it be possible to have a single source of UITests, currently it seems that tests are duplicated in the UIKit/SwiftUI apps. This would prevent having to remember to copy paste the same implementation twice when adding a new test. wdyt?

It makes sense. I thought about it, but in this PR I wanted to limit as much as possible the changes on the current codebase, in order to make it easier to review and limit regressions. Do you think we can do the refactoring on a separate PR or do you prefer if I rework this to add everything in a single PR?

Actually I gave the PR a look and besides the above concern everything looks pretty fine. If we can include this last change in this PR is would be great!

lechuckcaptain and others added 2 commits January 14, 2026 18:18
Set tableView.accessibilityIdentifier = "example_list" to match
SwiftUI's ContentView list identifier. This enables the unified
scrollContent API to work identically for both platforms.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move test resources (test_file.json, test_file.pkpass, locations_reduced.json)
to Examples/SharedUITests/Resources/ to be shared by both UIKit and SwiftUI
test targets.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
lechuckcaptain and others added 12 commits January 14, 2026 18:19
Add shared test helper extension with:
- wait(withTimeout:assertOnFailure:for:) for predicate-based waiting
- openTestSection(identifier:) for unified navigation that works for both
  UIKit (UITableView) and SwiftUI (UICollectionView) using the scrollContent
  API and generic descendant queries

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move NetworkRequests.swift and SBTUITestTunnelServer+Extension.swift
to Examples/SharedUITests/ for use by both UIKit and SwiftUI test targets.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move all UITests source files to Examples/SharedUITests/ for unified
test coverage across UIKit and SwiftUI targets.

Changes:
- Migrate 17 test files from UIKit tests to SharedUITests
- Add ScrollContentTests.swift from SwiftUI (unique tests for scrolling API)
- Update navigation patterns to use unified openTestSection(identifier:)
  instead of platform-specific app.tables.cells[].tap()
- Update setUp methods to use generic "example_list" identifier
- Remove duplicate test files from both UIKit and SwiftUI directories
- Keep only Info.plist files in original test directories

The unified navigation works for both UIKit (UITableView) and SwiftUI
(UICollectionView) by using:
- scrollContent(withIdentifier:toElementWithIdentifier:animated:) for scrolling
- Generic descendant queries for element tapping

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Configure both UIKit and SwiftUI projects to use SharedUITests:

UIKit (project.yml):
- SBTUITestTunnel_Tests target now sources from:
  - SBTUITestTunnel_Tests (Info.plist only, excludes *.swift)
  - ../SharedUITests (all shared test files)
- SBTUITestTunnel_TestsNoSwizzling remains unchanged (has its own
  specific tests for non-swizzling delegate approach)

SwiftUI (project.yml):
- UITests target now sources from:
  - UITests (Info.plist only, excludes *.swift)
  - ../SharedUITests (all shared test files)

Both targets will now compile the same test source files, enabling
unified test coverage across UIKit and SwiftUI platforms.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
KeepAliveTests.swift uses SBTWebServer which is an internal class
from GCDWebServer that is not publicly exposed via Swift Package
Manager. This test is specific to the CocoaPods UIKit configuration.

The test remains available in the UIKit target where the full
internal API is accessible via CocoaPods.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- SBTExtensionTableViewController1: Add 100 rows with proper accessibility
  (custom cell exposing label as staticText element)
- SBTExtensionCollectionViewController: Add ButtonCell for vertical and
  LabelCell for horizontal scroll directions with 100 items each
- SBTExtensionScrollViewController: New programmatic scroll view with
  Content 0-19, Button, and Content 20-39
- Main.storyboard: Change table view from static to dynamic mode

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update SBTTableViewController to push extension view controllers
  programmatically instead of using storyboard segues
- Remove storyboard scenes for SBTExtensionTableViewController1,
  SBTExtensionTableViewController2, and SBTExtensionScrollViewController
- Remove segue connections from extension cells in storyboard

This simplifies versioning and aligns with how the collection view
controllers were already implemented.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Complete migration from storyboard-based to programmatic UI:
- Remove Main.storyboard entirely
- Convert SBTAppDelegate from Objective-C to Swift
- Remove main.m (using @main attribute instead)
- Update Info.plist to remove UIMainStoryboardFile
- Convert view controllers to programmatic UI setup

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update MiscellaneousTests to use correct accessibility text format:
  - testTableViewScrolling: use "Label X" with space (matches SwiftUI)
  - testCollectionViewScrollingVertical: use buttons instead of staticTexts
- Fix notification center custom command to return "1"/"0" instead of "true"/"false"
- Adjust testScrollContentTableViewToOffset to use Label 50 at offset 0.5
  (matches actual UIKit scroll behavior with 100 rows at height 100)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add SceneDelegate to handle window scene management
- Update AppDelegate to support scene configuration
- Add UIApplicationSceneManifest to Info.plist
- Remove deprecated window property from AppDelegate

This fixes the "UIScene lifecycle will soon be required" warnings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants