Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI toggle not being toggled in UI test

I can't get UI tests to toggle a Toggle in a SwiftUI Form. It seems that app.switches[*name*].tap() does nothing. Does anyone else have experienced this? Ideas?

The code below is a demonstration of the issue. It's a simple form with four toggles that generates a int value based on the toggles positions.

I have the following SwiftUI view:

struct ContentView: View {
    
    @State var sw1: Bool = false
    @State var sw2: Bool = false
    @State var sw3: Bool = false
    @State var sw4: Bool = false
    
    
    var valueString: String {
        var ret: Int = 0
        if sw1 {
            ret = ret + 1
        }
        if sw2 {
            ret = ret + 2
        }
        if sw3 {
            ret = ret + 4
        }
        if sw4 {
            ret = ret + 8
        }
        return String(ret)
    }
    
    var body: some View {
        NavigationStack {
            Form {
                Section("Binary switches"){
                    Toggle("1", isOn: $sw1)
                        .accessibilityIdentifier("sw1")
                    Toggle("2", isOn: $sw2)
                        .accessibilityIdentifier("sw2")
                    Toggle("4", isOn: $sw3)
                        .accessibilityIdentifier("sw3")
                    Toggle("8", isOn: $sw4)
                        .accessibilityIdentifier("sw4")
                }
                Section("Value") {
                    Text(valueString)
                        .accessibilityIdentifier("value")
                        .accessibilityValue(valueString)
                }
            }
            .navigationTitle("Test Form")
        }
    }
}

And the following UI tests Code:

func testRandomSwitches() throws {
    let app = XCUIApplication()
    app.launch()
    
    // Get the binary switches
    let sw1 = app.switches["sw1"]
    let sw2 = app.switches["sw2"]
    let sw3 = app.switches["sw3"]
    let sw4 = app.switches["sw4"]
    
    // randomly switch on some of the switches
    let randomOnes = [sw1, sw2, sw3, sw4].map { _ in Bool.random() }
    if randomOnes[0] { sw1.tap() }
    if randomOnes[1] { sw2.tap() }
    if randomOnes[2] { sw3.tap() }
    if randomOnes[3] { sw4.tap() }
    
    // calculate the expected value
    let expectedValue = randomOnes.enumerated()
        .filter { $0.element }
        .map { 1 << $0.offset }
        .reduce(0, +)
    
    // get the value text and assert that it matches the expected value
    let value = app.staticTexts["value"].value as? String ?? ""
    XCTAssertEqual(value, String(expectedValue))
}

When I run this test, the switches never get toggled, and the value string always reads "0". The UITest code fails on XCTAssertEqual(value, String(expectedValue)). I'm not sure what I'm doing wrong.

If I try to record the toggle tap I always get the error "Timestamped Event Matching Error: Failed to find matching element".

Can anyone help me figure out why the switches aren't getting toggled in my UI tests?

like image 277
Martin Claesson Avatar asked Feb 02 '26 23:02

Martin Claesson


1 Answers

Figured it out. It seems that I need to access the first switch in the switch. Really weird. But I gess UI testing is weird. It would be much appreciated if anyone got a less hacky solution.

Non working code:

sw1.tap()

Working code:

sw1.switches.firstMatch.tap()
like image 79
Martin Claesson Avatar answered Feb 05 '26 14:02

Martin Claesson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!