Search code examples
ioscalabash

Can't touch second element in array


I'm trying to touch a UITextField using Calabash. When I use query("UITextField")[x], where x is the number in the array of text fields that are on screen, I can correctly query for just one text field. However, when I use touch("UITextField")[x] it will always touch the first text field. This happens when using the console and when using cucumber to run the tests.

Here's relevant info about my setup:

xcode-select --print-path
/Applications/Xcode.app/Contents/Developer

xcodebuild -version
Xcode 7.2
Build version 7C68

calabash-ios version
0.16.4

Solution

  • Try

    touch("UITextField index:x")
    

    where x == your index.

    Also, please update to calabash 0.17.0 :)

    Explanation

    The Calabash environment is composed of a client and a server. The server runs on the device/simulator as part of the app and receives commands/queries from the client. In this case, the client is the ruby interface through which you are interacting with the app.

    The client is responsible for sending enough info to the server to select objects on which to perform the gestures. Once the gestures / queries have been performed, results are sent back to the client as json / hashes, which is what you see in the console. The distinction is important: the server performs the queries, the client does not.

    By the time you are seeing the results of a query / gesture in the irb console, it has already been performed: the json that is returned simply represents the state of the views, not the actual views themselves.

    So when you are running

    touch("UITextField")[index]
    

    This is actually equivalent to

    touch_results = touch("UITextField")
    touch_results[index]
    

    In the first line, touch_results is receiving the json representation of the elements affected by performing touch on the results of querying for "UITextField", meaning that the touch event has already completed by the time you try to access the results with touch_results[index].

    Another way to think about it is this: Given res = touch(query), the query is the part used to specify the actual views, and res is just json that represents the state of those views / results of a query or gesture.

    In conclusion

    When you need more specificity on a query, the specifiers need to go inside the query. E.g.,

    touch("all UIScrollView UITextField marked:'some text' index:2")
    

    (this will search for all UIScrollViews , find any UITextFields inside of them which contain text matching 'some text', and return the 3rd of such results).

    For a full explanation of query language syntax, see the docs.