Moving Between Dynamic Picker Values with XCTest
XCTest provides an API for interacting with picker wheels - adjustToPickerWheelValue - but only when you know the value that you want to move to.
What if you don't know the values in the picker up front?
If you have dynamically-populated pickers, the provided API won't work very well for you. In order to use it without knowing the values up front, you'd have to traverse the entire picker before moving to the value you want.
However, if you can work out what value you want to get to, or how may values up or down you need to move, you can use the following two methods to interact with your pickers.
Below is an extension to XCUIElement which adds selectNextOption and selectPreviousOption, to be used on XCUIElement objects of type XCUIElementTypePickerWheel.
import XCTest extension XCUIElement { /// Scrolls a picker wheel up by one option. func selectNextOption() { let startCoord = self.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.5)) let endCoord = startCoord.coordinateWithOffset(CGVector(dx: 0.0, dy: 30.0)) endCoord.tap() } /// Scrolls a picker wheel down by one option. func selectPreviousOption() { let startCoord = self.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.5)) let endCoord = startCoord.coordinateWithOffset(CGVector(dx: 0.0, dy: -30.0)) endCoord.tap() } }
I've used +/-30.0 (points) as the Y-offset value from the centre of the picker wheel. If this doesn't work with your picker, try experimenting with different values.
You can use XCUIElement.value to extract information about the state of your picker.
/** Extracts the value of a picker from the `value` property of a picker wheel element, which shows the picker value and a description of the picker's position. - Parameter text: The value of the picker wheel element. - Returns: Tuple containing the currently-selected color, the current position of the picker wheel and the maximum position of the picker wheel. Positions are 1-indexed. */ private func getValuesForPickerText(text: String) -> (selectedValue: String, currentPosition: UInt, maximumPosition: UInt) { // Separate value let splitText = text.componentsSeparatedByString(",") let selectedValue = splitText[0] // Extract numbers var numbers = splitText[1].componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet) numbers = numbers.filter { $0 != "" } if numbers.count != 2 { XCTFail("Expected 2 numbers in picker wheel value but found \(numbers.count)") } let currentPosition = UInt(numbers[0])! let maximumPosition = UInt(numbers[1])! return (selectedValue: selectedValue, currentPosition: currentPosition, maximumPosition: maximumPosition) }
Once you've worked out where you want to be, you can use some straight-forward logic to determine whether you need to move up or down the picker.
You could also just start moving in one direction, and if you don't find your value, go back the other way - if you're OK with that.
/** Changes the selection of the given `pickerWheel` to the given `selectionPosition`. - Parameter pickerWheel: Picker wheel to change the selection of. - Parameter selectionPosition: Position of the picker to select. 1-indexed. */ func changePickerSelection(pickerWheel: XCUIElement, selectionPosition: UInt) { // Select the new value var valueSelected = false while !valueSelected { // Unwrap the current value of the picker wheel if let pickerValue = pickerWheel.value { let currentPosition = UInt(getValuesForPickerText(String(pickerValue)).currentPosition) if currentPosition == selectionPosition { valueSelected = true } else { if currentPosition > selectionPosition { pickerWheel.selectPreviousOption() } else { pickerWheel.selectNextOption() } } } else { XCTFail("Picker wheel value was nil") } } doneButton.tap() }












