Waiting for focus using predicate on XCUIElement [duplicate] - xcode-ui-testing

This question already has answers here:
Is there a way to find if the XCUIElement has focus or not?
(5 answers)
Closed 4 years ago.
I'm currently using NSPredicate to wait for conditions on XCUITest elements, as follows:
class func waitForCondition(condition: String, element: XCUIElement) -> Bool {
let predicate = NSPredicate(format: condition)
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
let result = XCTWaiter().wait(for: [expectation], timeout: 5)
return result == .completed
}
It works for most attributes, like "exists == 1", "isSelected == 1", "isHittable == 1", etc.
But what I want is a way to check for focus and there doesn't seem to be a condition that would validate that.
To be honest, I can't find a way to check for focus even in Xcode's autocomplete. I found the documentation for XCUIElementAttributes, an interface which is adopted by XCUIElement class:
https://developer.apple.com/documentation/xctest/xcuielementattributes
and it states the existence of the "hasFocus" Bool. But it really doesn't seem to exist outside of the documentation world.
I'm using Xcode 9.4.1, for the record.

You can write an extension for XCUIElement. Something like:
extension XCUIElement {
var hasFocus: Bool {
return self.value(forKey: "hasKeyboardFocus") as? Bool ?? false
}
}
This will return true/false.
You can use it like this:
if element.hasFocus == false {
element.tap()
}

Related

Problems checking to see if a value exists in Swift 2

I'm writing a quiz app and there is a table view to add a subject (The name is saved to core data) and when you select an index path it passes the subject to a detail view controller (this works just fine on its own) but what I'm having trouble with is checking to see if any cards exists (the subject entity has an NSOrderedSet of "Cards"). I keep getting a crash on my two attempts, I've done this in swift before with relationships and tableViews and it's always been fine so I'm not sure what the problem is here. Thank you for the help like always!
My first attempt, although it says "catch block is unreachable because no errors are thrown in do block", it crashes with "Bad Instruction" on the line after "do"
do {
if let firstCard = self.subject?.cards![0] as? Card {
self.currentCard = firstCard
}
} catch {
}
My second attempt, it crashes on the first line
if let firstCard = self.subject?.cards![0] as? Card {
self.currentCard = firstCard
}
My third attempt
if self.subject!.cards != nil {
self.currentCard = self.subject!.cards![0] as! Card
}
My fourth attempt, unwrapping both the subject property and subject, it not rings out self.subject.cards but still crashes
if let firstCard = self.subject!.cards?[0] as? Card {
self.currentCard = firstCard
}
Where the properties are declared
var draggableView = DraggableView!()
var subject : Subject?
var currentCard : Card?
var cardArray = [Card]()
The update with subject method (works perfectly, but put it here just for reference), the subject is passed from another class and this method called at the top of view did load.
func updateWithSubject(subject: Subject) {
if let subject = self.subject {
self.subject = subject
}
}
In all four of your attempts, you do a "forced" unwrapping (!) at some point, which is to be generally avoided. Also, you attempt to explicitly accessing index 0 in your NSOrderedSet; if the set is empty, accessing [0] will yield a runtime exception.
Instead, you could use the .array representation of the NSOrderedSet and use the .first (optional) property of array for a safe access test:
if let firstCard = self.subject?.cards?.array.first ...
I think there's some awkwardness going on in your updateWithSubject method. You're checking if there's a subject already initialized before assigning to it. If that's in your viewDidLoad and only there, the assignment will never happen. The forced unwrapping that follow will surely fail after.

How do you convert optional text input to Int in Swift 2, Xcode 7 beta using if let - toInt does not work

I'm having trouble converting optional input String to Int in order to do calculations on it.
let odoField = UITextField() // allows entry of text to iOS field
odoField.text = "12500" // simulated input
let odoString = odoField.text
// now here is where I get trouble...
if let odoInt = odoString.toInt() {
distance = Double(odoInt)
}
Apparently the toInt suffix is no longer part of Swift. I have tried the following:
if let odoInt = Int(odoString)() {
But then I get the error "Optional type String? is not unwrapped" and a suggestion to put a ! or ?, as in:
if let odoInt = Int(odoString!)() {
But then I STILL get the euro about unwrapping, with the suggestion that I add yet another !, then when I do that, another error that I get rid of the parens, like this:
if let odoInt = Int(odoString!)! {
And then I get ANOTHER error that "Initializer for conditional binding must have Optional type, not 'Int'."
I'm trying to create conditional unwrapping, here.
Help!
First thing to understand is that UITextField.text returns an optional string, so in your code, odoString is of type String?. Also, keep in mind that the Int constructor takes a String, not a String? so you have to unwrap the String? before you can use it. Just putting a ! after the variable (as in Int(odoString!)) will crash your app if the odoString is nil. Better would be something like this:
if let s = odoString, odoInt = Int(s) {
// odoInt is of type Int. It is guaranteed to have a value in this block
}
I've tested Daniel T's answer and it worked.
I have a situation where I want to get the result of a text field back as an optional Int. You can extend this to cover your case using the following code:
let odoInt = odoField.text != nil ? Int(odoField.text!) : nil
if let odoInt = odoInt {
// Use unwrapped odoInt here
}
Another option - for a more compact solution - is to use a flatMap:
let number = odoString.flatMap { Double($0) } ?? 0.0
In fact, it appears that the answer in Swift 2 (Xcode 7 beta 6) is simpler than anything above. The code does not choke on a nil value for odoString when I do e.g. the following:
if let odoInt = Int(odoString!) {
distance = Double(odoInt)
}
I therefore surmise, barring deeper knowledge to the contrary, that the compiler does treat this as "if the statement is True (the right side is valid), then define and initialize the variable, and continue with execution." I welcome further feedback. This does render unnecessary a lot of the extra code that is suggested above.

If not let - in Swift

is there is a way to negate the "if let" in swift?
This looks silly to me:
if let type = json.type {
} else {
XCTFail("There is no type in the root element")
}
I can't use XCTAssertNotNil, because json.type is a enum.
enum JSONDataTypes {
case Object
case Array
case Number
case String
}
Thanks a lot
EDIT: it is a:
var type: JSONDataTypes? = nil
Swift 2.0 (Xcode 7) and later have the new guard statement, which sort of works like an "if not let" -- you can conditionally bind a variable in the remainder of the enclosing scope, keeping the "good path" in your code the least-indented.
guard let type = json.type else {
XCTFail("There is no type in the root element")
}
// do something with `type` here
The catch to this is that the else clause of a guard must exit that scope (because otherwise you'd fall into code after that clause, where the guarded variables, like type above, are unbound). So it has to end with something like return, break, continue or a function that is known to the compiler to never return (i.e. annotated #noreturn, like abort()... I don't recall offhand if that includes XCTFail, but it should (file a bug if it's not).
For details, see Early Exit in The Swift Programming Language.
As for really-old stuff... There's no negated form of if-let in Swift 1.x. But since you're working with XCTest anyway, you can just make testing the optional part of an assertion expression:
XCTAssert(json.type != nil, "There is no type in the root element")
Here's how you do it:
if json.type == nil {
// fail
}
Another alternative I've used a few times:
switch json.type
{
case .None: // ...
case .Some(.Object): // ...
case .Some(.Array): // ...
case .Some(.Number): // ...
case .Some(.String): // ...
}
Since the ? is actually Optional<T> which is an enum on its own, defined as:
enum Optional<T> : Reflectable, NilLiteralConvertible
{
case None
case Some(T)
...
}

Swift: typecasting in a for loop

I'm a noobie in Swift. I'm trying to iterate over SKNodeTree and check if there are scary monster Nodes here. However I cannot figure out how to typecase the for loop. I have understood that this would be possible with "as" clause.
By the way, is comparing strings with == ok in Swift?
for monsterNode in self.children{
if (monsterNode.name? == "scary") {
println("scary monster here")
}
}
Comparing strings can be done by using == instead of isEqualToString, so thats fine. Your code should be like this:
for monsterNode in self.children as [SKNode] {
if (monsterNode.name? == "scary") {
println("scary monster here")
}
}
You can submit your cast inside the brackets []

How to replace lambda written in Where clause of Linq with equivalent delegate

I have an Query expression that uses a predicate type and lambda expression.
I am getting desired result with this. But I am not clear with how this expression is getting evaluated.
I tried to break this lambda expression by creating delegate and replacing condition under Where with delegate type.
If I have to rewrite the same thing with writing a delegate instead of anonymous type. What will be the syntax. How the delegate will be return for the same.
if (((DataTable)dgvAssignedRpm.DataSource).AsEnumerable()
.Where(row => row.Field<long>("FK_RPM_BTN_SETTING_ID") == objRpmButtonHolder.RpmSettingId).Count() > 1)
{
List<DataRow> listPkgBtnSettings = SearchForExistingSettingId();
}
void MethodSignature(...)
{
...
if (((DataTable)dgvAssignedRpm.DataSource).AsEnumerable()
.Where(RowCondition)
{
List<DataRow> listPkgBtnSettings = SearchForExistingSettingId();
}
...
}
// Where want a Func<T,bool> parameter
// T is the first parameter type (DataRow here)
// bool represents the return value
bool RowCondition(DataRow row)
{
return row.Field<long>("FK_RPM_BTN_SETTING_ID") == objRpmButtonHolder.RpmSettingId).Count() > 1
}
I assume the correct delegate replacement would be:
if (((DataTable)dgvAssignedRpm.DataSource).AsEnumerable().Where(
delegate(DataRow row) {
return (row.Field<long>("FK_RPM_BTN_SETTING_ID") == objRpmButtonHolder.RpmSettingId.Count() > 1);
}))
{
List<DataRow> listPkgBtnSettings = SearchForExistingSettingId();
}
But it's morning for me, so forgive me if I'm a bit off.
What the where desires is to give a DataRow as a parameter and a bool to return. You could just about fill in anything in the lambda or delegate, as long as it matches these requests.
To your question why it requests Func<> and how it works. The statement you're using is LINQ, so I found you a reference regarding this which can probably explain it better than me:
http://blogs.msdn.com/b/mirceat/archive/2008/03/13/linq-framework-design-guidelines.aspx
But yeah, the last type here in the Func<> is what it returns. (However, I can still recommend using the Lambda expression, as it's pretty clean, neat and serves the Func<> best.
(Also, look at what intellisence gives you when you write "new Func<....", it should give you a good idea of what Func wants and can do!)
Hope I was of help.

Resources