How to access the iOS 14 time picker in XCUITest

952 views Asked by At

I want to make use of the inline date picker style that was recently introduced in iOS 14. However, I need to make adjustments to a couple of XCUITests that include the previous picker wheel style.

The problem is I can't change the value of the time picker at all. I noticed that the time picker is not a picker nor a pickerWheel element in XCUITest; Instead, it's a textField element.

E.g. TextField, {{178.3, 401.7}, {74.7, 36.3}}, label: 'Time', value: 12:01

Changing its value like a typical textfield doesn't work at all (typeText doesn't do anything). I tried to access the picker wheels that seem to be inside the textfield, but checking for its descendants returns empty.

po timeInput.descendants(matching: .any).count
t =   799.62s Get number of matches for: Descendants matching type Any
0 // no descendants found

So how do I change the value of the time picker text field in XCUITest?

EDIT:

The date picker mode for the UIDatePicker is set to time, so I'm not really seeing the calendar view, just the time input field.

I put the date picker inside the contentView of a UITableViewCell, which is then added when another table view cell is tapped (i.e. it's dynamically added).

The date picker is configured like this:

picker.datePickerMode = .time
picker.date = Date(timeInterval: time, since: date)
picker.minuteInterval = intervals
if #available(iOS 14, *) {
    picker.preferredDatePickerStyle = .inline
}

Previously, the date picker is displayed as a picker wheel and I had no problem accessing it in the XCUITest. I could simply call this to adjust the value of the picker wheel: pickerWheels.element(boundBy: index).adjust(toPickerWheelValue: value)

However, with the date picker set to inline, the previous query no longer works. I also checked for picker and datePicker elements, but they also return empty results. I can see a textfield element that has a "Time" label and the value contains whatever value is set in the time picker.

(lldb) po app.pickers.count
t =  2270.22s Get number of matches for: Descendants matching type Picker
0 // No results

(lldb) po app.pickerWheels.count
t =  2277.07s Get number of matches for: Descendants matching type PickerWheel
0 // No results

(lldb) po app.datePickers.count
t =  2286.58s Get number of matches for: Descendants matching type DatePicker
0 // No results

(lldb) po app.textFields.count
t =  2302.55s Get number of matches for: Descendants matching type TextField
1 // 1 element matched

(lldb) po app.textFields
t =  2308.08s Requesting snapshot of accessibility hierarchy for app with pid 55829
t =  2308.46s Find: Descendants matching type TextField
t =  2308.47s Requesting snapshot of accessibility hierarchy for app with pid 55829
t =  2308.61s Find: Descendants matching type TextField
t =  2308.61s Requesting snapshot of accessibility hierarchy for app with pid 55829
Find: Target Application
  Output: {
    Application, pid: 55829, label: 'Projects'
  }
  ↪︎Find: Descendants matching type TextField
    Output: {
      TextField, {{178.3, 401.7}, {74.7, 36.3}}, label: 'Time', value: 01:00
    }

So I can't see any pickers, but I have textfield whose value is set to the date picker's time input value. I tried changing the textfield's value by using typeText but it doesn't seem to do anything at all.

2

There are 2 answers

1
Anna Fortuna On

I ended up creating a sample view controller which contains just the UIDatePicker to see if I can access it in XCUITest.

Interestingly, I was able to detect a datePicker element in the XCUITest which is something I wasn't able to do when dynamically adding the UIDatePicker in a table view.

The descendants of the datePicker looks like this:

Find: Descendants matching type DatePicker
Output: {
  DatePicker, {{89.3, 423.3}, {196.7, 53.3}}
}
↪︎Find: Descendants matching type Any
  Output: {
    Other, {{89.3, 423.3}, {196.7, 53.3}}
    Other, {{89.3, 431.3}, {196.7, 37.3}}
    Other, {{89.3, 431.3}, {196.7, 37.3}}, label: 'Time Picker'
    TextField, {{97.3, 431.3}, {74.7, 36.3}}, label: 'Time', value: 05:54
    SegmentedControl, {{178.0, 431.3}, {100.0, 36.3}}
    Button, {{178.0, 431.3}, {49.0, 36.3}}, label: 'AM'
    Button, {{228.0, 431.3}, {50.0, 36.3}}, label: 'PM', Selected
  }

The time input field is still a textfield element but I was able to change its value using typeText. I suspect that there's something in our codebase that handles the valueChanged delegate that causes the typeText to not work.

Bottomline, using typeText to change the value of the time input picker should work just fine.

0
ianWY On

Before using typeText to change its value, make sure it has focus. Try to tap the textfield first, and then the value can be changed via typeText.