Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerate all elements in Selenium Python bindings for Appium

I am trying to get started with Appium for testing my company's mobile applications. I wish to use the Python bindings to write the scripts, and I need to start with Android apps.

I have the Appium examples all working. I can run grunt android and the tests work, and I can run the android.py sample app.

But I'm a total newbie and I don't have a clear picture of how to identify the controls in my company's apps. I'm experienced with Python so I thought I would just build a list of control elements and introspect them.

I'm stuck! All of the methods like driver.find_elements_by_tag_name() require a specific identifier (or at least I haven't found any wildcard that works).

How can I introspect the Appium tree of elements that represents the Android app under test? How can I enumerate all the elements so I can introspect them? Is there a tree I can walk to find all elements in the app?

I was hoping I could figure out the elements without needing to get the source code for the apps, build the apps in Eclipse, etc. but I can do this if necessary.

P.S. I would prefer to use Python, but would be open to using something else to do the introspection if that works better. I could still write the actual tests in Python, unless the other language was significantly better somehow.

like image 791
steveha Avatar asked Mar 26 '13 21:03

steveha


2 Answers

I still would like a way to introspect the Selenium interface from Python. But I have found a workable way to get a clear image of how the app is laid out, and it's pretty easy to then figure out how to write the Selenium tests.

First, get your app running, either on a real device connected to your Android development computer or in an emulator. Basically if you run adb devices you want to see a single device, the one running your app. Next, run the uiautomatorviewer tool, and then click on the Device Screenshot toolbar icon. (There are only two toolbar icons: the first is the Open icon and looks like a file folder, and the one you want looks like a stack of mobile phones.)

Once you have done that, an image of your app appears, with a screenshot on the left, and a browsable tree outline on the right. The outline shows all the controls of the app, along with their text labels if any, and other information (such as whether the clickable property is true or false for that control).

One warning: the controls are shown numbered, but in the Selenium bindings, the numbers might not be the same. On the ApiDemos example app, the Graphics button has index number 4 as it is the fifth button, but to access it by its position I had to use index 5. Index 0 was a non-clickable object holding the text "API Demos", in a different FrameLayout object making up the header for the screen.

So, I was able to make this change to the android.py script:

#elem = driver.find_element_by_name('Graphics')
elem = driver.find_elements_by_tag_name('TextView')[5]

Comment out the driver.find_element_by_name() call, and instead find the sixth TextView in the entire app. That's not best practice but it shows that the uiautomationviewer results do let me view the stuff I need to know about the controls.

Now I know enough to do a little bit of introspection:

for elem in driver.find_elements_by_tag_name('TextView'):
    if elem.text == "Graphics":
        break
else:
    print("Could not find desired item")

This isn't better than just calling driver.find_element_by_name() but it shows that I am on the right track.

uiautomatorviewer is a practical solution to my problem. If you have a pure-Python one please let me know about it.

like image 165
steveha Avatar answered Oct 25 '22 09:10

steveha


Appium supports WebDriver's "page source" method. So you can do this:

# assume you have a driver object
import json

source = driver.page_source
source = json.loads(source)
# you can now work with source as a python object
like image 44
Jonathan Lipps Avatar answered Oct 25 '22 09:10

Jonathan Lipps