How do I insert element reference in an xpath string?

Question:

Given a UI element reference, how do I "append" a string to it so that I can find its next sibling element of type XCUIElementTypeStaticText?

The framework I am using contains a driver_helper.py file.

Within that file are the find_element & find_elements methods defined as:

def find_element(self, locator: tuple) -> WebElement:
return self.driver.find_element(*locator)
def find_elements(self, locator: tuple) -> list[WebElement]:
return self.driver.find_elements(*locator)

There is also a selector_const.py file containing declarations for the various types of selectors. The one I am using specifically for this question is:

BY_XPATH = MobileBy.XPATH

In the screen/page object file I am working on, I define a tuple
self.CHECKBOXES = (sc.BY_XPATH, '//XCUIElementTypeButton[@name="Square"]')

which I then use to create this variable:
checkboxes = self.driver_helper.find_elements(self.CHECKBOXES)

I want to find a sibling element to one of the checkboxes, but this snippet of code:

checkboxes = self.driver_helper.find_elements(self.CHECKBOXES)
sibling = (
            sc.BY_XPATH,
            f'{checkboxes[0]}/following-sibling::XCUIElementTypeStaticText',
        )
test = self.driver_helper.find_element(sibling)
print("checkbox 0 sibling element text: " + str(test))

fails with NoSuchElementError: An element could not be located on the page using the given search parameters.
I have included a screenshot of the domain of the screen to show that the checkboxes do exist and that there is an XCUIElementTypeStaticText right next to it

Domain of iOS app screen:

<XCUIElementTypeButton type="XCUIElementTypeButton" name="Square" label="Square" enabled="true" visible="true" accessible="true" x="15" y="428" width="20" height="21" index="22"/>
<XCUIElementTypeStaticText type="XCUIElementTypeStaticText" value="checkbox 1 text" name="checkbox 1 text" label="checkbox 1 text" enabled="true" visible="true" accessible="true" x="43" y="428" width="308" height="18" index="23"/>
<XCUIElementTypeButton type="XCUIElementTypeButton" name="Square" label="Square" enabled="true" visible="true" accessible="true" x="15" y="478" width="20" height="21" index="24"/>
<XCUIElementTypeStaticText type="XCUIElementTypeStaticText" value="checkbox 2 text" name="checkbox 2 text" label="checkbox 2 text" enabled="true" visible="true" accessible="true" x="43" y="478" width="260" height="35" index="25"/>
<XCUIElementTypeButton type="XCUIElementTypeButton" name="Square" label="Square" enabled="true" visible="true" accessible="true" x="15" y="542" width="20" height="21" index="26"/>
<XCUIElementTypeStaticText type="XCUIElementTypeStaticText" value="checkbox 3 text" name="checkbox 3 text" label="checkbox 3 text" enabled="true" visible="true" accessible="true" x="43" y="542" width="333" height="86" index="27"/>
<XCUIElementTypeButton type="XCUIElementTypeButton" name="Square" label="Square" enabled="true" visible="true" accessible="true" x="15" y="657" width="20" height="21" index="28"/>
<XCUIElementTypeStaticText type="XCUIElementTypeStaticText" value="checkbox 4 text" name="checkbox 4 text" label="checkbox 4 text" enabled="true" visible="true" accessible="true" x="43" y="657" width="320" height="52" index="29"/>
Asked By: kevin

||

Answers:

Store all the XPath in a variable:

main_element = "//*[@id="submenu1"]/a[2]"

element = driver.find_element(By.XPATH, main_element)


siblingElement = main_element + "/following-sibling::td"

element2 = driver.find_element(By.XPATH, siblingElement)
Answered By: AbiSaran

You can not insert WebElement object / reference in XPath string because Xpath expression should be string as you mentioned yourself.
What you do can is to locate the other element based on the existing element.
For example, if you want to find the /following-sibling::td based on existing element you can do it as following:

element = driver.find_element(By.XPATH, '//*[@id="submenu1"]/a[2]')
siblingElement = element.find_element(By.XPATH, './following-sibling::td')
  1. In the second line I’m applying find_element method on element object, not on driver object.
  2. The XPath expression is staring with a dot . there to notify that this relative XPath is related to the current node.
  3. find_element(By.XPATH, is used now while find_element_by_xpath is deprecated.
    UPD
    In case you want to find sibling elements of a list of elements you can do something like this:
base_elements = driver.find_elements(By.XPATH, 'the_xpath_locator')
for element in base_elements:
    siblingElement = element.find_element(By.XPATH, './following-sibling::td')
Answered By: Prophet

If you can add methods in the driver_helper.py, you can implement there a method using the solution provided in this answer
But if you can not do that, you need to change the code of your sibling variable. Now you are trying to put an element into XPATH and this can not work as you put an object into a string.
So, the workaround is to put there the XPATH string which you use to find the parent element.
As you get all the checkboxes into a list, you can iterate through the them and get the siblings like this:

for i in range(len(checkboxes)):
    sibling = (sc.BY_XPATH, f'(//XCUIElementTypeButton[@name="Square"])[{i+1}]/following-sibling::XCUIElementTypeStaticText')
    test = self.driver_helper.find_element(sibling)
    print(f"checkbox {i+1} sibling element text: {test.text}")
Answered By: Eugeny Okulik