XCUITest Ideas
SwiftUI not supported adjusting picker wheel value
xcode 13.2.1/swift 5.5.2
Historically
for lazy fellows just jump over to “How it works?”
Hello everyone, probably many of you met this issue when Picker Wheel adjustments is not working properly or doesn’t work at all (completely dead for UI Automation Testing). The most common reason why, is starting to use SwiftUI instead of UIKit.
Digging in issue
Step 1. Error tell us “Unsupported picker wheel…..”. So let’s check if path to element is right(it’s obviously since error tell as about element) try to adjust from debugger and see the log.
Step2. Try to find any other solution to work around: swipeUp() and swipeDown() while condition will be true, and this is the bad one 100%. Trying to set in code base parameters to adjust even ideas about API but under the hood nothing is reachable since UIDatePicker was programmed not for that.
Solution: was obvious for those who familiar with Appium or any other cross platform tools for Mobile testing. We will rotate wheel via coordinates.
This is gitHub link for project with two DatePickers with 2 and 3 wheels and solution for adjusting them.
How it works?
Step1. Let’s create an extension for XCUIElemet. Then we will need two functions currentPosition() to return value of the current picker position as String and core of adjustment idea is rotateUp() function.
In different sources, I found : each wheel notch is about 30px high, so tapping y — 30 rotates up. y + 30 rotates down. BUT in my case 20 was the size.
Step2. Core of function adjustPickerWheelValueTo(value: String, WheelNumberIs: Int) is while loop. The interesting point here is to make sure condition will be succeed you need wait till rotation is completed and compare with XCUIElement, comparing with value is FAIL, only after including XCUIElement and .waitForExistence(timeout: 1) while loop start to work properly. It was a really PAIN POINT!
Also you don’t want to leave while loop without break for whole night(CI tool is not trust guy, it can take your while loop and make it crazy) so secureRotateCount will break a while loop after 100 iterations.
Also you can pass whole element instead Int
Step3. For my case, I have single view app with two date picker (technically one Date picker) one of them has 2 wheels, another 3 wheels.
For two wheels passing year and month as String, and (in this case) hardcoded wheel by index 0 or 1 (better store element in variable)
For 3 wheels passing hours, mins, daytime as String, and (in this case) hardcoded wheel by index 0 , 1, 2 (better store element in variable)
Notes: best way to assert datePicker value is using Date class for any cases.
In Test class not the all tests adjusting all 3 wheel only test4()
That’s all from my side.
I hope it was helpful!