How to locate, using Xpath, an input field without using its id

1.2k views Asked by At

I'm working with a web page with the following HTML where I want to identify the first <input> field inside the <span> using a text_field from within a page-object.

<div id="131:">  Please enter your name:
<span class="autocompspan " style="position:static;">
    <input style="position: static;" class="autocompinput yui-ac-input" id="132:" name="132:" 
    onfocus="juic.fire(&quot;132:&quot;,&quot;_focus&quot;,event);" 
    onchange="juic.fire(&quot;132:&quot;,&quot;_despatchChange&quot;,event);" 
    onblur="juic.fire(&quot;132:&quot;,&quot;_blur&quot;,event);" size="60" 
    onkeydown="juic.fire(&quot;132:&quot;,&quot;_onkeydown&quot;,event);" 
    onkeyup="juic.fire(&quot;132:&quot;,&quot;_onkeyup&quot;,event);" aria-disabled="false" value="" 
    role="combobox" aria-autocomplete="list" aria-owns="132:_divList" 
    aria-activedescendant="132:_divAD" findtype="proxy" delimchar="" hideusername="false" 
    fetchusername="false" autocomplete="off" type="text">
    <input value="" id="132:_hidden" name="132:_hidden" type="hidden">
</span>
</div>

If I use :id => '132:' to identify the field things work fine. I.e. text_field(:target_user_name, :id => '132:' ) works.

The issue is that this HTML is generated by the underlying app (SAP) which does not always generated the same value for the <input> field id so using the id cannot be relied upon to consistently identify the element. So, given the above HTML what other ways might I go about reliably finding this <input> field.

I've tried the following, none of which work. Most of them time out waiting for the element to be located.

text_field(:target_user_name, :xpath => "//*[@class='autocompinput yui-ac-input' and @role = 'combobox']" )
text_field(:target_user_name, :xpath => "//*[@class='autocompinput' and @role = 'combobox']" )
text_field(:target_user_name, :xpath => "//span/input[@class='autocompinput yui-ac-input' and @role = 'combobox']" )
text_field(:target_user_name, :xpath => "//input[@class='autocompinput yui-ac-input' and @role = 'combobox']" )
text_field(:target_user_name, :class => 'autocompinput yui-ac-input')

Any thoughts?

3

There are 3 answers

5
Justin Ko On BEST ANSWER

When an element does not have unique identifiable attributes, you should look at the elements around it. In this case, there is user visible text that helps a user identify the purpose of the field. That same text can be used to identify the element in Watir.

As the surrounding div only contains the labelling text, you can search for that div by its text and get the only text field in it:

browser.div(text: 'Please enter your name:').text_field

As a page-object accessor:

text_field(:target_user_name) { div_element(text: 'Please enter your name:').text_field_element }
5
SelThroughJava On

In this particular case you can check the first input field after 'Please enter your name:' text using below xpath:

//div[text()='Please enter your name:']//following::input[1]

In general if you encounter fields that does not have a unique identifier you can rely on static text or fields and then use xpath functions such as following, preceding etc.

6
titusfortner On

Firstly, Watir is designed to make it so that you shouldn't have to use XPATH.

It depends on how many different elements/ids are on the page, but I've found that using regular expressions often works well with dynamically generated ids. So either grab the id and use it elsewhere:

id = browser.text_field(id: /\d\d\d/).tr(':', '')

or just use it directly:

text_field(:target_user_name, id: /\d\d\d:/)