How to retrieve variable data from a label in UI tests - ios

This is what I have so far and I am simply trying to get the result that is output in a label and test it against set results:
func testExample() {
let app = XCUIApplication()
let enterRomanNumeralsHereTextField = app.textFields["Enter roman numerals here"]
enterRomanNumeralsHereTextField.tap()
let convertButton = app.buttons["Convert"]
//1
enterRomanNumeralsHereTextField.typeText("LL")
convertButton.tap()
XCTAssertTrue(app.staticTexts.element(matching:.any, identifier: "Roman Numerals").label == "NotValidRomanNumber")
//2
enterRomanNumeralsHereTextField.typeText("LXXXIX")
convertButton.tap()
XCTAssertEqual(app.otherElements.containing(.staticText, identifier:"Roman Numerals").element.value as! String, "89")
//3
enterRomanNumeralsHereTextField.typeText("")
enterRomanNumeralsHereTextField.typeText("LXXVIII")
convertButton.tap()
XCTAssertEqual(app.otherElements.containing(.staticText, identifier:"Roman Numerals").element.value as! String, "")
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
The first attempt(labeled 1) gives me a build error saying "cannot call value of non function type XCUIElement.
The second attempt builds but the test fails because even though the label does indeed produce the right value, the test is reading the label as blank which brings us to my third attempt which passes the test because I compared it to a blank label, which is what its showing.
So as I said above I'm just wondering how exactly to retrieve the label value that is a result of a "calculation" or button press.

Unfortunately when a UILabel is accessed in a UITest the XCUIElement's value property is not set with the text property of the UILabel. It is always empty.
XCUIElement also has a label property which you can use for your purpose. You only have to make sure that you are not setting the accessibilityLabel on your UILabel. Use accessibilityIdentifier instead:
In your app:
label.accessibilityIdentifier = "Roman Numerals"
In your UITest:
XCTAssertEqual(app.staticTexts.element(matching:.any, identifier: "Roman Numerals").label, "89")

Related

UI Test Case XCUIElementTypeQueryProvider tableRows and tableColumns count is 0

I am trying to test whether the UITableView has at least first cell available or not.
func testFirstCellIsAvailable() throws {
let app = XCUIApplication()
app.launch()
let tablesQuery = app.tables
XCTAssertNotNil(tablesQuery.cells.staticTexts["John"], "First Cell should be John")
}
This is one of the simplest way to find the TableView is loaded or not.
However , I see XCUIElementQuery has tableRows and tableColumns, when I check the value it's always zero. So the question is when do we use tableRows and tableColumns
For the above example value of app.tableRows.count and app.tableColumns.count is 0.
tableColumns and tableRows are usually seen in 2D tables, while "flat" UITableView consist of cells. For example, you can see such elements if you create a table in macOS Notes application and inspect XCUIApplication

How do I convert Collection of [UILabel] to string text to display on ViewController?

I am trying to display the same information on a collection of [UILabel], but I am getting this error,
Value of type '[UILabel]?' has no member 'text'
I am getting the specific error on this line in my code.
storagetypelabel.text = "\(booking.storageType.uppercased()) STORAGE"
Would love some input on how to alter the way my property.text label is typed.
Since I hooked up multiple UILabel to one [UILabel] collection, when I call the [UILabel] property, I should be able to display the same information for all the connected labels in the collection right?
text is a property of a single UILabel not an array , To set the text for all labels use
let str = "\(booking.storageType.uppercased()) STORAGE"
storagetypelabel.forEach { $0.text = str }

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)
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)

Weird error in accessing the text of UIButton in swift

When I write a simple function such as this:
#IBAction func buttonTapped(theButton:UIButton) {
println(theButton.titleLabel.text);
}
It gives me an error: UILabel doesn't have a label called text.
However, when I change it to this:
#IBAction func buttonTapped(theButton:UIButton) {
println(theButton.titleLabel?.text);
}
It works fine, but it prints out something like this:
Optional("1");
What I am doing wrong? I am expecting a value of 1. But it is printing out Optional("1") and secondly, it is working fine when println(theButton.titleLabel?.text);
You can get directly from
let title = theButton.currentTitle!
Optional chaining makes the result optional, so you are printing optional value: https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/OptionalChaining.html
With optional binding you can print the value only if it exits.
if let text = theButton.titleLabel?.text {
println(text)
} else {
// text doesn't have value
}
#Kirsteins's answer shows how to obtain the button label text in a safe manner.
Remember that:
UIButton has a titleLabel, which is an optional UILabel.
UILabel has a text property, which is an optional String
so there are 2 optionals in the chain. You can use optional binding as in #Kirsteins's answer, or use forced unwrapping:
let text = theButton.titleLabel!.text!
which however I discourage using, because if any of the 2 is nil you'll have a runtime exception. But for completeness it's worth mentioning.
The buttons titleLabel property returns an optional UILabel, that means it's possible that the button doesn't have a titleLabel.
var titleLabel: UILabel? { get }
If you don't set a title to the button, then the button doesn't have a titleLabel property, the iOS framework adds the titleLabel only if the button has a title, I think this happens to reduce memory.
This is why you have to put the "?" (is called optional chaining you can read about it here http://bit.ly/1vrSOi1) in that line, but this usually get auto completed by Xcode itself.
Kirsteins answers it correctly but misses one small detail
if your object can be nil (optional) you need to check first if it exists to then access its value, like this:
if let text = theButton.titleLabel?.text {
println(text)
}
but you can also ignore the if and just call it like this:
let text : String = theButton.titleLabel?.text
// If theButton.titleLabel don't exists then text will be nil
this happen if the IBOutlet was declared with ? but if you declare with ! that means you know that it could be nil, but you never want it to be nil, for a IBOutlet i prefer this approach since if the IBOutlet is not connected then maybe something is worn with my code.
#IBOutlet var theButton : UIButton!
// and get text value as
theButton.titleLabel!.text
this will ensure theButton.titleLabel could be nil, but in this part of code it is required, hope this helps to understand the difference between optional (?) and optional required (!)

Extra argument "named" in call

#IBAction func rerollTapped(sender: UIButton) {
var pickupLines:[String] = [
"aye babe, you from iraq cause you should babhdad ass up",
"HBB asdjksja asjd aj iueihieu",
"Dollar Menu akjshdskjhdksj",
"askdjkjashkjhd",
"skajshdkasjhdka"
]
var randomPickupLine = arc4random_uniform(UInt32(pickupLines.count))
self.pickupLabel.text = UILabel(named: randomPickupLine)
I'm attempting to randomize pickup lines and display the random line in a label. When the Re-roll button is tapped the next random pickup line is shown in the label.
It seems the problem is with this last line, it says "Extra argument "named" in call"
Any thoughts?
UILabel doesn't have an init method that takes a name (initWithName: in Objective-C) so that's why that is an "extra argument" (to the init() method). Perhaps you were thinking of UIImage?
Also, your randomPickupLine is a number (the index), not the string value.
Also, you are trying to assign label (a UI element) to the text property of another label (which expects a String)

Resources