Fix an issue where nested ScrollViews would not be detected properly (#69)
* Fix an issue where nested ScrollViews would not be detected properly * Fix nested ScrollView issue on iOS 13 * Clean up implementation of siblingOrAncestorOfType to avoid extraneous searches * Adjust naming for correctness * Add nested ScrollView tests for macOS This also fixes the same issue iOS had, where nested ScrollViews would not be correctly detected on macOS 11+ * Update UIKit ScrollView tests to match AppKit ones * Add changelog entry for nested scrollview fixes * Change NSScrollView lookup mechanism for macOS 10.15 to match UIKit behavior
This commit is contained in:
parent
f246b0715c
commit
461fa7b608
|
@ -7,6 +7,7 @@ Changelog
|
|||
- Add Github Action
|
||||
- Added `.introspectTextView()`.
|
||||
- Update CircleCI config to use Xcode 12.4.0
|
||||
- Fixed nested `ScrollView` detection on iOS 14 and macOS 11
|
||||
|
||||
## [0.1.2]
|
||||
|
||||
|
|
|
@ -245,6 +245,13 @@ public enum TargetViewSelector {
|
|||
return Introspect.previousSibling(containing: TargetView.self, from: viewHost)
|
||||
}
|
||||
|
||||
public static func siblingContainingOrAncestor<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
if let sibling: TargetView = siblingContaining(from: entry) {
|
||||
return sibling
|
||||
}
|
||||
return Introspect.findAncestor(ofType: TargetView.self, from: entry)
|
||||
}
|
||||
|
||||
public static func siblingOfType<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
guard let viewHost = Introspect.findViewHost(from: entry) else {
|
||||
return nil
|
||||
|
@ -252,6 +259,13 @@ public enum TargetViewSelector {
|
|||
return Introspect.previousSibling(ofType: TargetView.self, from: viewHost)
|
||||
}
|
||||
|
||||
public static func siblingOfTypeOrAncestor<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
if let sibling: TargetView = siblingOfType(from: entry) {
|
||||
return sibling
|
||||
}
|
||||
return Introspect.findAncestor(ofType: TargetView.self, from: entry)
|
||||
}
|
||||
|
||||
public static func ancestorOrSiblingContaining<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
if let tableView = Introspect.findAncestor(ofType: TargetView.self, from: entry) {
|
||||
return tableView
|
||||
|
|
|
@ -83,9 +83,9 @@ extension View {
|
|||
/// Finds a `UIScrollView` from a `SwiftUI.ScrollView`, or `SwiftUI.ScrollView` child.
|
||||
public func introspectScrollView(customize: @escaping (UIScrollView) -> ()) -> some View {
|
||||
if #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) {
|
||||
return introspect(selector: TargetViewSelector.ancestorOrSiblingOfType, customize: customize)
|
||||
return introspect(selector: TargetViewSelector.siblingOfTypeOrAncestor, customize: customize)
|
||||
} else {
|
||||
return introspect(selector: TargetViewSelector.ancestorOrSiblingContaining, customize: customize)
|
||||
return introspect(selector: TargetViewSelector.siblingContainingOrAncestor, customize: customize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,11 @@ extension View {
|
|||
|
||||
/// Finds a `NSScrollView` from a `SwiftUI.ScrollView`, or `SwiftUI.ScrollView` child.
|
||||
public func introspectScrollView(customize: @escaping (NSScrollView) -> ()) -> some View {
|
||||
return introspect(selector: TargetViewSelector.ancestorOrSiblingContaining, customize: customize)
|
||||
if #available(macOS 11.0, *) {
|
||||
return introspect(selector: TargetViewSelector.siblingOfTypeOrAncestor, customize: customize)
|
||||
} else {
|
||||
return introspect(selector: TargetViewSelector.siblingContainingOrAncestor, customize: customize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds a `NSTextField` from a `SwiftUI.TextField`
|
||||
|
|
|
@ -55,8 +55,8 @@ private struct ListTestView: View {
|
|||
@available(macOS 10.15.0, *)
|
||||
private struct ScrollTestView: View {
|
||||
|
||||
let spy1: () -> Void
|
||||
let spy2: () -> Void
|
||||
let spy1: (NSScrollView) -> Void
|
||||
let spy2: (NSScrollView) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
|
@ -64,18 +64,44 @@ private struct ScrollTestView: View {
|
|||
Text("Item 1")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy1()
|
||||
self.spy1(scrollView)
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy2()
|
||||
self.spy2(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15.0, *)
|
||||
private struct NestedScrollTestView: View {
|
||||
|
||||
let spy1: (NSScrollView) -> Void
|
||||
let spy2: (NSScrollView) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy2(scrollView)
|
||||
}
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy1(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15.0, *)
|
||||
private struct TextFieldTestView: View {
|
||||
let spy: () -> Void
|
||||
|
@ -175,16 +201,57 @@ class AppKitTests: XCTestCase {
|
|||
wait(for: [expectation1, expectation2, cellExpectation1, cellExpectation2], timeout: TestUtils.Constants.timeout)
|
||||
}
|
||||
|
||||
func testScrollView() {
|
||||
func testScrollView() throws {
|
||||
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
var scrollView1: NSScrollView?
|
||||
var scrollView2: NSScrollView?
|
||||
|
||||
let view = ScrollTestView(
|
||||
spy1: { expectation1.fulfill() },
|
||||
spy2: { expectation2.fulfill() }
|
||||
spy1: { scrollView in
|
||||
scrollView1 = scrollView
|
||||
expectation1.fulfill() },
|
||||
spy2: { scrollView in
|
||||
scrollView2 = scrollView
|
||||
expectation2.fulfill()
|
||||
}
|
||||
)
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
|
||||
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
|
||||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testNestedScrollView() throws {
|
||||
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
var scrollView1: NSScrollView?
|
||||
var scrollView2: NSScrollView?
|
||||
|
||||
let view = NestedScrollTestView(
|
||||
spy1: { scrollView in
|
||||
scrollView1 = scrollView
|
||||
expectation1.fulfill()
|
||||
},
|
||||
spy2: { scrollView in
|
||||
scrollView2 = scrollView
|
||||
expectation2.fulfill()
|
||||
}
|
||||
)
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
|
||||
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
|
||||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testTextField() {
|
||||
|
|
|
@ -139,8 +139,8 @@ private struct ListTestView: View {
|
|||
@available(iOS 13.0, tvOS 13.0, macOS 10.15.0, *)
|
||||
private struct ScrollTestView: View {
|
||||
|
||||
let spy1: () -> Void
|
||||
let spy2: () -> Void
|
||||
let spy1: (UIScrollView) -> Void
|
||||
let spy2: (UIScrollView) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
|
@ -148,18 +148,43 @@ private struct ScrollTestView: View {
|
|||
Text("Item 1")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy1()
|
||||
self.spy1(scrollView)
|
||||
}
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy2()
|
||||
self.spy2(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, macOS 10.15.0, *)
|
||||
private struct NestedScrollTestView: View {
|
||||
|
||||
let spy1: (UIScrollView) -> Void
|
||||
let spy2: (UIScrollView) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ScrollView(showsIndicators: true) {
|
||||
Text("Item 1")
|
||||
|
||||
ScrollView(showsIndicators: false) {
|
||||
Text("Item 1")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy2(scrollView)
|
||||
}
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy1(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0, tvOS 13.0, macOS 10.15.0, *)
|
||||
private struct TextFieldTestView: View {
|
||||
let spy: () -> Void
|
||||
|
@ -316,16 +341,58 @@ class UIKitTests: XCTestCase {
|
|||
wait(for: [expectation1, expectation2, cellExpectation1, cellExpectation2], timeout: TestUtils.Constants.timeout)
|
||||
}
|
||||
|
||||
func testScrollView() {
|
||||
func testScrollView() throws {
|
||||
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
var scrollView1: UIScrollView?
|
||||
var scrollView2: UIScrollView?
|
||||
|
||||
let view = ScrollTestView(
|
||||
spy1: { expectation1.fulfill() },
|
||||
spy2: { expectation2.fulfill() }
|
||||
spy1: { scrollView in
|
||||
scrollView1 = scrollView
|
||||
expectation1.fulfill()
|
||||
},
|
||||
spy2: { scrollView in
|
||||
scrollView2 = scrollView
|
||||
expectation2.fulfill()
|
||||
}
|
||||
)
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
|
||||
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
|
||||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testNestedScrollView() throws {
|
||||
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
var scrollView1: UIScrollView?
|
||||
var scrollView2: UIScrollView?
|
||||
|
||||
let view = NestedScrollTestView(
|
||||
spy1: { scrollView in
|
||||
scrollView1 = scrollView
|
||||
expectation1.fulfill()
|
||||
},
|
||||
spy2: { scrollView in
|
||||
scrollView2 = scrollView
|
||||
expectation2.fulfill()
|
||||
}
|
||||
)
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
|
||||
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
|
||||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testTextField() {
|
||||
|
|
Loading…
Reference in New Issue