XPath changing the current node

Hello all,

I’m new to appium and I’m evaluating it for use in automated testing of an iPad application. So far my research has indicated it is the best fitting solution for our current testing framework since it has native python 3.x support, doesn’t rely on a particular testing framework, and it has the ability to test both iOS and Android. That being said I’ve been monkeying around with it the last few days and have a question related to XPath.

The general layout here is that we already have an application developed for iPads running iOS 8.x, and it has been a pain in the past to get the developers to go back and add ID attributes to GUI elements. I have not worked with XPath before, but reading through the working draft on W3C it seems to be very powerful and may fit my needs. Anyway to the point: I have Appium 1.3.6 running on a Mac Book running OS X 10.10.1, connected to an iPad Mini Retina. I’ve had no problems getting the application deployed from the Appium server onto the iPad. I’ve also gotten the inspector running nicely which gave me some hints as to how to use XPath the get handles on some of the objects. I’ve gotten the latest git repository of the appium client for python loaded onto another Linux machine on the same local network.

I can successfully get a handle onto our UIATabBar object using XPath by referencing it from the document root, but things fall apart when I try to access any UIAButtons on the tab bar via the tab bar. Perhaps I’m using XPath incorrectly, but a simple example will suffice to demonstrate the problem:

howard@0x0badbeef:~/repos/personal/python/appium$ python3.4
Python 3.4.2 (default, Nov  7 2014, 13:43:47) 
[GCC 4.7.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from appium import webdriver
>>> caps = {
...   "platformName": "iOS",
...   "platformVersion": "8.1",
...   "deviceName": "iPad Retina (921221VB-E282-46C4-BCF7-AE44DA7026F1)",
...   "automationName": "Appium",
...   "newCommandTimeout": "999999",
... }
>>> driver = webdriver.Remote("http://192.168.1.25:4723/wd/hub", caps)
>>> tabBar = driver.find_element_by_xpath("//UIAApplication[1]/UIAWindow[1]/UIATabBar[1]")
>>> btn1 = tabBar.find_element_by_xpath("child::UIAButton[1]")
Traceback (most recent call last):
...
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.

>>> btn1 = tabBar.find_element_by_xpath("child::UIAButton[@name='Videos']")
Traceback (most recent call last):
...
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.

>>> btn1 = tabBar.find_element_by_class_name("UIAButton")
>>> btn1
<appium.webdriver.webelement.WebElement object at 0x7f191ac1c5f8>
>>> btn1 = driver.find_element_by_xpath("//UIAApplication[1]/UIAWindow[1]/UIATabBar[1]/UIAButton[@name='Videos']")
>>> btn1
<appium.webdriver.webelement.WebElement object at 0x7f191ac1c0f0>

I had assumed that by calling the “find_element_by_xpath()” function on the WebElement object, the given web element (tabBar) would have become the current node in the XPath search. Is that incorrect? How would I go about searching from the TabBar rather than searching the entire DOM for the given object?

Thanks for any help!

Hi @aghoward,

Please try below:

btn1 = tabBar.find_element_by_xpath("/child::UIAButton[1]")

And let me know if it works.

The “/” is required as you are looking for immediate descendants from the current node.
Thanks,
Sujata

Thank you for the input, but that is also a no-go:

>>> btn1 = tabBar.find_element_by_xpath("/child::UIAButton[1]")
Traceback (most recent call last):
....
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.
>>> btn1 = tabBar.find_element_by_xpath("/descendant::UIAButton[1]")
>>> btn1.get_attribute("name")
''
>>> btn1 = tabBar.find_element_by_xpath("/descendant::UIAButton[2]")
Traceback (most recent call last):
....
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.
>>> btn1 = tabBar.find_element_by_xpath("./child::UIAButton[1]")
Traceback (most recent call last):
....
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.

To be clear the tabBar actually has 6 buttons directly under it, which are visible at the time of executing these statements. I’m not sure which button it thinks it found the one time that it did work using “/descedant::UIAButton[1]”.

Any other ideas?

Unfortunately you cannot call find_element_by_xpath() on an Webdriver Element, apparently that feature has not been implemented. See here: xpath selector doesn't work if search context is an element (not a driver) · Issue #2558 · appium/appium · GitHub

You can however call other find methods like find_element_by_class() against an element to find children, use XPATH axes, or use some custom code to programmatically compose XPATH by concatenating some XPATH snippets together then calling self.driver.find_element_by_xpath(your_custom_composed_xpath)

1 Like

Ahh, thanks for the info! It looks like there wasn’t a good explanation as to why this was not implemented, though I feel it would make XPath lookups significantly quicker if it doesn’t have to start at the document root every time.

I may be able to work something out to find stuff by class name

Hi @Christopher_Graham,

Thanks for pointing that out.

Regards,
Sujata

Post back here when you come to some conclusion about what workaround you come up with. I’ve built my entire test platform around XPATH as it’s so flexible and powerful. So not being able to run find_by_xpath against elements is fairly annoying.

I was tempted to implement xpath searches on elements myself until I saw this mess in the code https://github.com/appium/appium-atoms/blob/published/atoms/find_element.js. Which is where I assume the actual implementation of searches occurs. Is it somewhere else? Hard to tell when everything is on one line :frowning: