Search code examples
swiftuiapple-watchpickerxcuitestuitest

XCTest cannot find picker or any of its picker wheel values (SwiftUI + Apple Watch)


I have a timer app for the apple watch. the homescreen has 2 pickers. one for time and one for background sounds. I am trying to write tests for both but am still stuck on the first picker.

the goal: Test launches. selects first picker. default value is 1. I want to either swipe up (or somehow select) 3 minutes. then tap the go button. then make sure the timer is at 3:00 instead of 1:00.

the actual results: test launches. XCTest cannot find picker and therefor cannot change the picker value. When I go into the app hierarchy I am seeing that the picker element is not in the hierarchy as a picker but as an element of type Other. Not only that but it says there is only 1 picker value and it is of type Static Text. I'm not sure why this is happening. I have nearly identical code in the iPhone version of the app and do not have this problem. not only that but the hierarchy only shows the selected value. despite the picker having value of 1, 2, 3, 4, 5, 10, 15, 20, 30, 45, 60 the only available is the initial value of 1. when I try to use swipeUp() it sets the value to 45. I'm not sure why. swiping up says in the app hierarchy that the picker (of value type other NOT picker) has only one child element and that is StaticText with the label and identifier values set to 45.

here's the code for the picker:

struct InitialViewTimePicker: View {

    @EnvironmentObject var timerViewModel: TimerViewModel

    var body: some View {
        Picker(selection: self.$timerViewModel.timerModel.timerVal, label: Text("How many minutes?")) {
            ForEach(0..<self.timerViewModel.getTimes().count, id: \.self) {
//                Text("1").tag(1).accessibilityIdentifier("1")
//                Text("2").tag(2).accessibilityIdentifier("2")
//                Text("3").tag(3).accessibilityIdentifier("3")
//                Text("4").tag(4).accessibilityIdentifier("4")
//                Text("5").tag(5).accessibilityIdentifier("5")
// this produces the same result
                Text("\(self.timerViewModel.getTimes()[$0])")
                    .tag(self.timerViewModel.getTimes()[$0])
                    .accessibilityIdentifier("\(self.timerViewModel.getTimes()[$0])")
            }
        }
        .foregroundColor(Color.ColorPrimary)
        .pickerStyle(.wheel)
        .accessibilityIdentifier("TimePicker")
   }
}

here's the app hierarchy:

app hierarchy showing there is no picker or options for picker

here's the latest test:

func test_quietMIND_Watch_AppMinutesPicker_CanBeAdjusted(){
   let timePicker = app.otherElements["TimePicker"]
   timePicker.tap()
   timePicker.staticTexts["1"].exists
   print("timePicker.staticTexts[1].exists = \(timePicker.staticTexts["1"].exists)")
   let time = timePicker.staticTexts.matching(identifier: "1")
   timePicker.swipeUp()
   print("\(timePicker.value)")
   print("time.element.exists : \(time.element.exists)")
   let selectedTime = app.otherElements.staticTexts["3"]
   selectedTime.isSelected
   XCTAssertEqual(app.staticTexts.element.label, "03:00")
}

So yeah. how do I tell the app hierarchy that the ui element picker is in fact a picker? how do I make sure the picker is a picker and has all its child values? and how do I change the value of the picker?


Solution

  • So it seems I have found a work around.

    .swipeUp()
    

    just does a fast swipe up to the near bottom of values. not sure why

    .swipeUp(velocity: 25)
    

    swipes up by one element at the desired pace. the velocity value is irrelevant to the number of swipes but it can be extremely slow. even 25 is slower than ideal. not sure exactly how the speeds are determined or relevant.

    when you go into the app hierarchy you see there's a major difference between swipeUp() and swipeUp(velocity: Int). using the regular swipeUp() it will only show the value it was swiped to in the app hierarchy. in this case it is 45. but if you use swipeUp(velocity: Int) it lists all elements that have been swiped over. so swiping up twice will have the children StaticText elements every picker value swiped over. so swiping up twice reveals the child static text elements of 1, 2, and 3. not sure why the difference but there is one.

    anyone who can explain the why of this would be greatly appreciated.