Get Label text with XCode UI Automation - ios

I created a simple app where the user enters their name into a TextField, clicks a button, and then a label above the textField changes its text to "Hello Name!".
I'm trying to verify that this works correctly with a UI Automation Instrument. I am able to enter text and click a button but when I try to verify the labels new value it doesn't return the correct value. Here is the code,
var input = target.frontMostApp().mainWindow().textFields()["NameInput"];
var button = target.frontMostApp().mainWindow().buttons()["SubmitButton"];
input.setValue("Sonny");
button.tap();
// This is not returning the labels correct value!
var label = target.frontMostApp().mainWindow().elements()["HelloLabel"].value();
if(label != "Hi Sonny!")
{
UIALogger.logFail("The Hello Label did not have the correct value! "+label);
}
else
{
UIALogger.logPass("The Hello Label was correct :D ");
}
I've tried using label() and value() but they both return the "HelloLabel". Has anyone encountered this and found a solution to retrieve the labels updated value?
Here is the xcode code if its needed...
#IBOutlet weak var MyLabel: UILabel!
#IBOutlet weak var MyName: UITextField!
#IBAction func sayHi(sender: AnyObject) {
MyLabel.text = "Hi \(MyName.text)!"
}

Related

UI Test iOS 13 - Textfield retaining old value after being cleared

On iOS13 I've noticed that after a textfield is cleared programatically the value for that textfield in the UI tests doesn't update.
In my UI test:
Text is entered into the textfield.
Some action happens which causes my code to clear the textfield (in this case tapping return on the on screen keyboard).
The value of the textfield is checked and it still contains the text that was present before it was cleared.
Here is the code I'm using to clear the textfield:
func clearInput() {
textField.text = nil
}
Here is the check I'm using in my UI test:
XCTAssert((createPasswordPage.passwordSecureTextField.value as? String) == "")
This fails on iOS13 but passes on older versions such as iOS12.
Any idea why this might be happening?
Example:
Code
class PasswordViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var button: UIButton!
...
#IBAction func buttonTapped(_ sender: Any) {
// Clear the text
textField.text = nil
}
}
UI Test
func testTextClearing() {
let page = PasswordPage()
// Enter text
page.passwordTextField.tap()
page.passwordTextField.typeText("some text")
// Tap button causing text to clear from the textfield
page.button.tap()
XCTAssert((page.passwordTextField.value as? String) == "")
}

How do I get a static variable to appear as a field in an iOS app?

I added a label to my storyboard and did a CTRL drag to my ViewController.swift file, set as an Outlet and gave it a name but it's not clear to me how to print a variable such as the following to my label.
var userName = "Ted"
In Swift playgrounds I can run the following and it prints the variable just fine but I can't make it do that in the label/IBOutlet once I compile the app.
var userName = "Ted"
print(userName)
Here's my ViewController so far:
import UIKit
class ViewController: UIViewController {
var userName = "Ted"
#IBOutlet var userNameLabel: UILabel? = nil
override func viewDidLoad() {
super.viewDidLoad()
print(userName)
}
}
I'm using Xcode 9.3.1 and Swift 4.
Since your label is an outlet and it is connected through your storyboard, change:
#IBOutlet var userNameLabel: UILabel? = nil
to:
#IBOutlet var userNameLabel: UILabel!
Then in viewDidLoad, instead of print, set the label's text:
userNameLabel.text = userName
Every label have one property called text which is used to set/get value to/from label for example::
lblObj.text = "text you want to display"
print(lblObj.text) // output:: "text you want to display"
text property will only except string type, since your username is of type string you can assign it like below
userNameLabel.text = userName

Sum of three textfield value without clicking a button (Swift - Xcode)

I'm currently having problems for my label to read the addition of 3 textfield values automatically, without a button function action. As such i only want my textfield to be an Int input only. There's a screenshot attached below for better reference. Appreciate those who can help me with this. Thanks!
ViewController
import UIKit
class TryingoutController: UIViewController {
#IBOutlet var impact: UITextField!
#IBOutlet var rigour: UITextField!
#IBOutlet var response: UITextField!
#IBOutlet var total: UILabel!
One way is to add self as the target to the text fields, for the control event .editingChanged
impact.addTarget(self, action: #selector(textChanged), for: .editingChanged)
// do the same for other textfields
Then declare a textChanged method. This should handle what happens when the texts in the text fields change. One implementation would be to add up all the values in the text fields (if any, and is valid) and display it in the label.
func textChanged() {
let impactValue = Int(impact.text!)
let rigourValue = Int(rigour.text!)
let responseValue = Int(response.text!)
total.text = String(describing:
(impactValue ?? 0) + (rigourValue ?? 0) + (responseValue ?? 0)
)
}
Optionally, you can conform to UITextFieldDelegate:
class TryingoutController: UIViewController, UITextFieldDelegate {
}
and implement shouldChange according to this answer by Thuggish Nuggets. Then, set the delegates of the text fields to self:
impact.delegate = self
// do the same for other text fields.

bindTo rx_text of a UITextField did not trigger the UITextField's emit event

I'm a new one to learn RxSwift.
I modified the Simple Numbers example in the RxSwift Example App, which will add three numbers into a result number.
I add a testStr UITextField, and an upperCase UILabel. I map testStr to uppercase and bindTo the upperCase label, that's good. And I also map testStr to its length, and bindTo the num1 field. Strange things happen, although the contents of the num1 field changes, it does not emit any event, so it has no effect on the result label. Even if I input some number into another number field, the result number does not count the num1.
Have I made any wrong use of bindTo? In what way can I make the num1 emit an event?
Thanks!!!
#IBOutlet weak var num1: UITextField!
#IBOutlet weak var num2: UITextField!
#IBOutlet weak var num3: UITextField!
#IBOutlet weak var result: UILabel!
#IBOutlet weak var testStr: UITextField!
#IBOutlet weak var upperCase: UILabel!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Observable.combineLatest(num1.rx_text, num2.rx_text, num3.rx_text) {
(textval1, textval2, textval3) -> Int in
return (Int(textval1) ?? 0) + (Int(textval2) ?? 0) + (Int(textval3) ?? 0)
}
.map{$0.description}
.bindTo(result.rx_text)
.addDisposableTo(disposeBag)
let obStr = testStr.rx_text
obStr
.map {$0.uppercaseString}
.bindTo(upperCase.rx_text)
.addDisposableTo(disposeBag)
obStr
.map{ $0.characters.count }
.map{ $0.description }
.bindTo(num1.rx_text)
.addDisposableTo(disposeBag)
}
You need to use a Subject such as Variable to store the value. You can see an example of this in this answer in the section called Using Variables.
The reason it doesn't work is because rx_text will only omit a next element when it's changed by the user, not programmatically (as you're doing). This is because rx_text is really using this method from UIControl to get notified of changes to the field:
public class UIControl : UIView {
public func addTarget(target: AnyObject?, action: Selector, forControlEvents controlEvents: UIControlEvents)
}
However, that method does not call the action method on target when the change happens programmatically. Only when it happens due to a user changing something.
So, you should see a next event if you were to change the field programmatically and then the user were to tap into (or out of) the field. However, that's not what you want.
Instead, refer to that answer I linked you to and it will work.

Save and Load text on UITextField

I am struggling for some hours at a problem. Basically, I have a simple Swift app. It goes like this. In my 1st view controller I have 3 text fields I want to fill them with information and a "Next" button.
Pressing the "Next" button will send me to a new UIViewController where I will have a "Back" button. Upon pressing the back button, I will be send back to 1st page with the 3 text fields.
What I want is: if I complete the text fields with informations, press Next and then Back, I want the text fields to be filled with that information.
I managed to move between the views with buttons, but I can't save the information. Can you provide me a little help?
#IBOutlet weak var txtb1: UITextField!
#IBOutlet weak var txtb2: UITextField!
#IBOutlet weak var txtb3: UITextField!
#IBAction func next(sender: AnyObject) {
text1 = self.txtb1.text!
text2 = self.txtb2.text!
text3 = self.txtb3.text! }
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (!text1)
{
txtb1.text = text1
}
}
If you are wanting to pass variables to different views you will have to use the prepareForSegue function before you segue into that view controller.
This allows the variables to be accessed by the view controller.
Override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
{
if segue.identifier == "segue_name"
{
let theDestination = segue.destinationViewController as! newViewController
theDestination.variable = "testing"
theDestination.variable2 = "testing2"
}
}
Then inside your second view controller you will have to declare variable and variable2 as shown:
var variable:String!
var variable2:String!
These will then be able to be used in the second view controller inside the viewDidLoad method.
Ok. I managed to fix a little of the problem, that button wasn't linked accordingly so the function was not executing. Here it is the code:
var text1 = ""
#IBOutlet weak var txtb1: UITextField!
#IBAction func next(sender: AnyObject) {
text1 = self.txtb1.text! // text1 = "I am taking value"
}
// when i press the back button
override func viewDidLoad() {
super.viewDidLoad()
if (!numarInmatriculare.isEmpty)
{
txtb1.text = text1 //here text1 = Null. the value is not saved
}
}
I want the value to be saved and displayed back on text field.
I also tried to use static varibiles but I am prompet with error.
static var numar:String = ""
numar = text1
//static member 'numar'cannot be used on instance of type 'viewcontroller'
You no need to do anything for this case, once text field filed then you clicking next button you wrote some code below i shown
text1 = self.txtb1.text!
text2 = self.txtb2.text!
text3 = self.txtb3.text!
Please first you remove the code,Once data filled in text filed, its automatically retain, after you clicking next button then come back it automatically it will retain, when your current view is poping then only your data will deallocate.

Resources