Reputation: 881
I have a VStack
with code relying on the .onTapGesture
method. Something like this:
VStack {
if imageShow {
Image("image1")
}
else {
Image("image2")
}
}
.onTapGesture {
imageShow.toggle()
}
I'd like to test this behavior within a UI Test using XCTest. The problem is, I don't know how to access the VStack in order to apply a .tap()
to it. I can't seem to find the method attached to app
. A button is found using app.buttons[]
but there doesn't seem to be an equivalent for app.VStack
or app.HStack
.
Also, I've tried converting this code to wrap the VStack
in a Button
, but for some reason, this overlays my image, distorting the preferred behavior.
Updating with full VStack
code snippet that I am working with:
VStack(alignment: .leading, spacing: 0) {
ZStack {
if self.create_event_vm.everyone_toggle == true {
Image("loginBackground")
.resizable()
.accessibility(identifier: "everyone_toggle_background")
}
HStack {
VStack(alignment: .leading, spacing: 0) {
Text("Visible to everyone on Hithr")
.kerning(0.8)
.scaledFont(name: "Gotham Medium", size: 18) .foregroundColor(self.create_event_vm.everyone_toggle ? Color.white : Color.black)
.frame(alignment: .leading)
Text("Public event")
.kerning(0.5)
.scaledFont(name: "Gotham Light", size: 16)
.foregroundColor(self.create_event_vm.everyone_toggle ? Color.white : Color.black)
.frame(alignment: .leading)
}
.padding(.leading)
Spacer()
}
}
}
.frame(maxWidth: .infinity, maxHeight: 74)
.onTapGesture {
self.create_event_vm.everyone_toggle.toggle()
}
.accessibility(identifier: "public_event_toggle")
.accessibility(addTraits: .isButton)
Upvotes: 6
Views: 2835
Reputation: 3478
The solution for me was to create an un-styled GroupBox to "wrap" any content inside.
After that we can assign an accessibilityIdentifier to it.
It doesn't disrupt the screen readers or change the layout.
Code:
/// Groupbox "no-op" container style without label
/// to combine the elements for accessibilityId
struct ContainerGroupBoxStyle: GroupBoxStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.content
}
}
extension GroupBoxStyle where Self == ContainerGroupBoxStyle {
static var contain: Self { Self() }
}
extension View {
/// This method wraps the view inside a GroupBox
/// and adds accessibilityIdentifier to it
func groupBoxAccessibilityIdentifier(_ identifier: String) -> some View {
GroupBox {
self
}
.groupBoxStyle(.contain)
.accessibilityIdentifier(identifier)
}
}
Usage:
struct TestView: View {
var body: some View {
HStack {
Image(systemName: "person")
TextField("Name", text: .constant("Name"))
}
.padding()
.onTapGesture {
print("Stack Tap")
}
.groupBoxAccessibilityIdentifier("NAME_TEXTFIELD")
}
}
Locating in XCTest:
app.descendants(matching: .any)["NAME_TEXTFIELD"]
// OR
app.otherElements["NAME_TEXTFIELD"]
Note: GroupBox
is unavailable in tvOS and watchOS.
Upvotes: 5
Reputation: 1037
I find that otherElements["x"]
doesn't work for ZStack, VStack or HStack. Instead I identify something else, like a Text, and try to get using staticTexts["x"]
.
Upvotes: 1
Reputation: 258117
Try the following approach
VStack {
if imageShow {
Image("image1")
}
else {
Image("image2")
}
}
.onTapGesture {
imageShow.toggle()
}
.accessibility(addTraits: .isButton)
.accessibility(identifier: "customButton")
and test
XCTAssertTrue(app.buttons["customButton"].exists)
Upvotes: 6