SwiftUI 应用程序的 UI 测试在计时器过去后找不到设置了可访问性标识符的元素

问题描述

应用:

该应用有一个标签云,它使用由 Text 触发的 ZStack 每隔几秒在 ForEach 视图中添加和删除标签到 ObservableObjectZStack 有一个 accessibilityIdentifier 集。

界面测试:

在 UI 测试中,我首先设置了 XCTWaiter。经过一段时间后,我检查 XCUIElement (ZStack) 与 accessibilityIdentifier 是否存在。 之后,我为 ZStack 类型的所有后代查询 XCUIElement .staticText 我还查询 XCUIApplication 以获取 .staticText

类型的后代

以下问题:

XCTWaiter 设置得太长时,等待时间太长。它不再找到带有其标识符的 ZStack XCUIElement

如果 XCTWaiter 设置为较短的等待时间或被移除,则会找到 ZStack XCUIElement。但它永远不会找到它的 .staticText 类型的后代。但它们确实存在,因为我可以发现它们是 XCUIApplication 本身的后代。

我的假设:

我假设 ZStack 及其标识符只能通过测试找到,只要它没有后代。并且因为它此时还没有任何后代,稍后为其后代查询 ZStack XCUIElement 也会失败,因为 XCUIElement 似乎只代表 ZStack它被捕获的时间。

或者,也许我在错误的位置附加了 accessibilityIdentifierZStack,或者 SwiftUI 会在有后代时立即删除它,我应该只向后代添加标识符。但这是否意味着我只能从 XCUIApplication 本身查询后代,而不能从另一个 XCUIElement 查询?那会使 .children(matching:) 变得毫无用处。

这是启用测试的 SwiftUI 中单视图 iOS 应用的代码。

MyAppUITests.swift

import XCTest

class MyAppUITests: XCTestCase {

    func testingTheInitialView() throws {
        
        let app = XCUIApplication()
        app.launch()
        
        let exp = expectation(description: "Waiting for tag cloud to be populated.")
        _ = XCTWaiter.wait(for: [exp],timeout: 1) // 1. If timeout is set higher
        
        let tagCloud = app.otherElements["TagCloud"]
        XCTAssert(tagCloud.exists) // 2. The ZStack with the identifier "TagCloud" does not exist anymore.
        
        let tagsDescendingFromTagCloud = tagCloud.descendants(matching: .staticText)
        XCTAssert(tagsDescendingFromTagCloud.firstMatch.waitForExistence(timeout: 2)) // 4. However,it never finds the tags as the descendants of the tagCloud
        
        let tagsDescendingFromApp = app.descendants(matching: .staticText)
        XCTAssert(tagsDescendingFromApp.firstMatch.waitForExistence(timeout: 2)) // 3. It does find the created tags here.
        
    }
}

ContentView.swift:

import SwiftUI

struct ContentView: View {
    private let timer = Timer.publish(every: 3,on: .main,in: .common).autoconnect()
    @ObservedObject var tagModel = TagModel()
    
    var body: some View {
        ZStack {
            ForEach(tagModel.tags,id: \.self) { label in
                TagView(label: label)
            }
            .onReceive(timer) { _ in
                self.tagModel.addNextTag()
                if tagModel.tags.count > 3 {
                    self.tagModel.removeOldestTag()
                }
            }
        }.animation(Animation.easeInOut(duration: 4.0))
        .accessibilityIdentifier("TagCloud")
    }
}

class TagModel: ObservableObject {
    @Published var tags = [String]()
    
    func addNextTag() {
        tags.append(String( Date().timeIntervalSince1970 ))
    }
    func removeOldestTag() {
        tags.remove(at: 0)
    }
}

struct TagView: View {
    @State private var show: Bool = true
    @State private var position: CGPoint = CGPoint(x: Int.random(in: 50..<250),y: Int.random(in: 100..<200))
    
    let label: String
    
    var body: some View {
        let text = Text(label)
            .position(position)
            .opacity(show ? 0.0 : 1.0)
            .onAppear {
                show.toggle()
            }
        return text
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)