在 UI 测试我的 SwiftUI 应用程序时如何访问 VStack

Bon*_*teq 6 xctest xcuitest swiftui

我有一个VStack依赖该.onTapGesture方法的代码。像这样的东西:

VStack {
    if imageShow {
        Image("image1")
    }
    else {
        Image("image2")
    }
}
.onTapGesture {
    imageShow.toggle()
}
Run Code Online (Sandbox Code Playgroud)

我想使用 XCTest 在 UI 测试中测试此行为。问题是,我不知道如何访问 VStack 以便.tap()对其应用 a 。我似乎找不到附加的方法app。使用 找到了一个按钮app.buttons[],但似乎没有app.VStack或 的等效项app.HStack

另外,我尝试将此代码转换为将 包装VStack在 a 中Button,但由于某种原因,这覆盖了我的图像,扭曲了首选行为。

VStack使用我正在使用的完整代码片段进行更新:

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)
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 6

尝试以下方法

VStack {
    if imageShow {
        Image("image1")
    }
    else {
        Image("image2")
    }
}
.onTapGesture {
    imageShow.toggle()
}
.accessibility(addTraits: .isButton)
.accessibility(identifier: "customButton")
Run Code Online (Sandbox Code Playgroud)

并测试

XCTAssertTrue(app.buttons["customButton"].exists)
Run Code Online (Sandbox Code Playgroud)

  • 它给我以下错误:“无法获取匹配快照:找到多个匹配元素”。看起来它正在将自己附加到 VStack 中的每个“Text()”视图。 (3认同)

Ale*_*sky 5

我的解决方案是创建一个无样式的GroupBox以“包装”其中的任何内容。
之后我们可以为其分配一个accessibilityIdentifier 。
它不会干扰屏幕阅读器或更改布局。

代码:

/// 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

struct TestView: View {
    var body: some View {
        HStack {
            Image(systemName: "person")
            TextField("Name", text: .constant("Name"))
        }
        .padding()
        .onTapGesture {
            print("Stack Tap")
        }
        .groupBoxAccessibilityIdentifier("NAME_TEXTFIELD")
    }
}
Run Code Online (Sandbox Code Playgroud)

位于 XCTest 中:

app.descendants(matching: .any)["NAME_TEXTFIELD"]
// OR
app.otherElements["NAME_TEXTFIELD"]
Run Code Online (Sandbox Code Playgroud)

注意:GroupBox在 tvOS 和 watchOS 中不可用。