Search code examples
iosxcodexcode-ui-testingui-testinguiprogressview

How to UITest UIProgressView?


Situation:

I want to UI-test my progress view and see if it's progress has increased.

What I've tried:

By using a breakpoint in my UI-test and using the po print(app.debugDescription), I can successfully see and access the UIProgressView element.

It's called: Other, 0x6080003869a0, traits: 8589935104, {{16.0, 285.5}, {343.0, 32.0}}, identifier: 'progressView', label: 'Progress', value: 5%

I access it with let progressView = secondTableViewCell.otherElements["progressView"], which works, as .exists returns true.

Now, to check progress, the description above hints at the 'value' property, that is currently at 5%. However, when I try progressView.value as! String or Double or whichever, I cannot seem to get the property as it isn't NSCoder-compliant.

Question:

Is it possible to UI-test a UIProgressView and use it's progress value?

My final custom solution:

Using the value property (when casting to String) somehow does work now. As I wanted to check if progress increased over time, I strip the String to get the numeric progress in it to compare. Here is my solution I use now:

// Check if progress view increases over time
let progressView = secondTableViewCell.otherElements["progressView"]
XCTAssert(progressView.exists)

let progressViewValueString = progressView.value as! String
// Extract numeric value from '5%' string
let progressViewValue = progressViewValueString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()

// Let progress increase
sleep(3)

let newProgressViewValueString = progressView.value as! String
let newProgressViewValue = newProgressViewValueString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
XCTAssert(newProgressViewValue > progressViewValue)

Solution

  • XCUIElement conforms to XCUIElementAttributes which gives you access to a value property of type Any?

    The actual type of value at runtime depends on which kind of UI element you are querying. In case of a UIProgressView it is of type __NSCFString, which is a concrete subclass of NSString. Which means you can safely cast it to String:

    This works (provided that you set your progress view's accessibility identifier to "progressView"):

    func testProgressView() {
       let app = XCUIApplication()
       app.launch()
    
       let progressView = app.progressIndicators["progressView"]
       // alternative (if the above query does not work):
       // let progressView = app.otherElements["progressView"]
       let currentValue = progressView.value as? String
       XCTAssertEqual(currentValue, "5 %")
    }
    

    Weirdly in some cases the progressIndicator query does not work. In that case you can try a otherElements query (see comment in above code)