ViewInspector
ViewInspector copied to clipboard
Inspection of onTap gesture on custom Layout
I have been using ViewInspector with good success, but seem to have become stuck on how to correctly inspect a view and wonder if you could help me get my thinking straight:
Given this view:
public struct PersonCardView: View {
var data: PersonCardData
let actions: TimelineEntryActions
public var body: some View {
PersonCardViewContent(data: data)
.onTapGesture {
actions.onTap()
}
}
}
public struct PersonCardViewContent: View {
var data: PersonCardData
static let minHeight: CGFloat = 250
public var body: some View {
PersonCardHStack {
PersonCardTextBlock(data: data)
if let image = data.image {
PersonCardImage(image: image)
}
}
.padding(EdgeInsets(
top: 0,
leading: TimelineViewMetrics.cardPaddingLeading,
bottom: 0,
trailing: 0
))
.frame(minHeight: PersonCardView.minHeight)
.cardBackground()
}
}
I can successfully test that the onTap
gesture is correctly wired up with this test:
func testA10_viewIsCorrectlyWiredToAction_onTap() throws {
// Setup actions to test
let expectation = expectation(description: "Action called")
let minimalData = PersonCardData(
type: .undefined,
timestamp: Date(),
givenName: "",
familyName: "",
jobTitle: "",
department: "",
organization: "",
image: nil
)
let actions = actions(expectation, onTap: true)
// Inspect view
let view = PersonCardView(data: minimalData, actions: actions)
let target = try view.inspect().find(PersonCardViewContent.self)
// Process under test
try target.callOnTapGesture()
// Expectation
waitForExpectations(timeout: 0.1)
}
However, the only reason that the view is structured with the separate PersonCardViewContent
was to get the test to pass. The actual SwiftUI view I originally wanted to test was basically the same, but with the onTapGesture just attached directly to the contents of the body:
public struct PersonCardView: View {
var data: PersonCardData
let actions: TimelineEntryActions
static let minHeight: CGFloat = 250
public var body: some View {
PersonCardHStack {
PersonCardTextBlock(data: data)
if let image = data.image {
PersonCardImage(image: image)
}
}
.padding(EdgeInsets(
top: 0,
leading: TimelineViewMetrics.cardPaddingLeading,
bottom: 0,
trailing: 0
))
.frame(minHeight: PersonCardView.minHeight)
.cardBackground()
.onTapGesture {
actions.onTap()
}
}
}
In this case, I tried using .find(PersonCardView.self)
as the target, but that would not trigger the expectation as the onTapGesture is not on that view, it's on the first child of that view...
PersonCardHStack
is a custom SwiftUI layout, and I am unsure how to target it or its contents. I am sure this is a key contributor. It seems like in the PRs that have previously been addressed that it is possible to now target contents of custom layouts, but I am clearly missing something.
I would appreciate any pointers, so I don't have to change my view structure just to make this action wiring testable.