How to populate drop down when it is built using an input tag using java and selenium - selenium

I have a drop down built with extJS.
<input id="combo-1786-inputEl" data-ref="inputEl" type="text" size="1" name="Query Category" placeholder="Select query category" role="combobox" aria-hidden="false" aria-disabled="false" aria-readonly="false" aria-invalid="true" aria-required="true" aria-haspopup="true" aria-expanded="false" aria-autocomplete="list" class="x-form-field x-form-required-field x-form-text x-form-text-default x-form-invalid-field x-form-invalid-field-default x-form-empty-field x-form-empty-field-default" autocomplete="off" data-componentid="combo-1786" data-errorqtip="<ul class="x-list-plain"><li>This field is required</li></ul>" aria-describedby="combo-1786-ariaErrorEl">
As we can see the tag used is 'input' and not 'select'.
So when I looked up about how to populate it, most answers were made under the assumption that it was created using a 'select' tag and it did not work.
Also the drop downitems are fetched from DB only when I click on the arrow on the dropdown:
So as a result of this, the drop down items cant be found on the page source.
Can someone one please suggest how to populate such downs using the best practice?
P.S-I do have a workaround, but its not at all good code practice and not at all generic:
driver.findElement(By.xpath("//*[#id='combo-1731-trigger-picker']")).click();//clicking on the arrow key of the drop down.
//Once the drop down item comes, I am trying to replicate pressing the keyboard arrow key,by sending down arrow key to the drop down item(web element)
//This works for me because I know the extact position of my drop down item in the drop down item list.It will stop working if the postion of the drop item changes
//so below loop just presses the down arrow key required number of times.
for(int i=0;i<5;i++){
driver.findElement(By.xpath("//*[#id='combo-1731-inputEl']")).sendKeys(Keys.ARROW_DOWN);
}
driver.findElement(By.xpath("//*[#id='combo-1731-inputEl']")).sendKeys(Keys.ENTER);
If you read the comments mentioned along with the above code, then you can understand how fragile the logic is.
Please help.

You are trying to click/ select the item in the drop down correct?
Do the drop down items have unique id's? If so you should be able to just pass it the specific xpath id.
I personally use Css to find elements, in that case it would be
driver.find_element(By.CSS_SELECTOR,'#combo-1731-trigger-picker').click()
driver.find_element(By.CSS_SELECTOR, '#combo-1731-inputEl > nth:child(x)').click()
where x = the count of your drop down item.
or if they have unique id's then use
driver.find_element(By.CSS_SELECTOR, '#theUniqueIdGoesHere').click()
I wrote a whole weeks worth of tests, using xpath selectors, it was painful day to day running the test and watching it fail. Going back and changing everything to Css selectors has saved me many head aches since I started writing Auto tests.
Edit: you could try the following,
driver.findElement(By.linkText("Your Links Text Here")).click();
This will only work if each links text is unique as well, if not it will select the first one it finds.
If these work for you would you mind accepting my answer?

Related

Selenium (Python): Strategy for locating item with inconsistent Xpath

writing a Python selenium script to auto-populate many forms. On one particular form, I have to add the entry, then click the "Add Another" button in order add the next entry. I successfully located the "Add Another" button via find.element(By.XPATH, xx), which works on the first two iterations with an xpath that looks like this:
//*[#id="7d977bf8-9863-5be0-ab89-c90cff57953d"]/div[3]/div[2]/div[2]/div/div[1]/div/div[2]/button[1]
But it is unable to locate the button on the third pass through. I found that the xpath changed ever so slighty: The index of the second /div in the path changed from "2" to "6":
//*[#id="7d977bf8-9863-5be0-ab89-c90cff57953d"]/div[3]/div[6]/div[2]/div/div[1]/div/div[2]/button[1]
My immediate reaction was to code for a NoSuchElementException and if the original is not found, search for the second. But given the observed behavior, I'm not sure I can be certain it's just those two Xpaths. I may need to "Add Another" 40 or 50 times, I could end up with a block of code that tries 10 or 20 xpaths (I am not a web developer, so I have no idea why this change of path is happening, or when it may happen again on the same Form).
So I'm trying to come up with another method to locate this button. Here is the HTML:
<button class="grid-button" data-bind="click: function() { imagetrend.formComposer.controlHandlers.grid.addAnotherButtonClickHandler($context) }, css: { 'disabled' : imagetrend.FormComposer.isReadOnly($context) }, disableEvent: { 'click': imagetrend.FormComposer.isReadOnly.bind(null, $context) }"> <i class="fa fa-lg fa-plus"></i> Add Another </button>
I don't see any unique element in there that I can search by given what I know about Selenium: Tag, ID, CSS_Selector...I tried locating by the "fa fa-lg fa-plus" class, but that isn't found (I think I've deduced that's for the large plug sign in the button).
So is there some sort of bulletproof way I can find this element without coding for every potential xpath I find along the way? Thanks.
I didn't find an alternate method to identify that element, but found that with only that second /div index changing, a wildcard character suited my needs.
so it ended up as:
driver.find_element(By.XPATH,'//*[#id="7d977bf8-9863-5be0-ab89-c90cff57953d"]/div[3]/div[*]/div[2]/div/div[1]/div/div[2]/button[1]').click()
And that XPATH matches any instance of the button that may pop up.
Thanks to Prophet and Akzy for keeping me on my toes!

Selenium XPath find element where second text child element contains certain text (use contains on array item)

The page contains a multi-select dropdown (similar to the one below)
The html code looks like the below:
<div class="button-and-dropdown-div>
<button class="Multi-Select-Button">multi-select button</button>
<div class="dropdown-containing-options>
<label class="dropdown-item">
<input class="checkbox">
"
Name
"
</label>
<label class="dropdown-item">
<input class="checkbox">
"
Address
"
</label>
</div>
After testing in firefox developer tools, I was finally able to figure out the xPath needed in order to get the text for a certain label ...
The below XPath statement will return the the text "Phone"
$x("(//label[#class='dropdown-item'])[4]/text()[2]")
The label contains multiple text items (although it looks like there is just one text object when looking at the UI) in the label element. There are actually two text elements within each label element. The first is always empty, the second contains the actual text (as shown in the below image when observing the element through the Firefox developer tool's console window):
Question:
How do I modify the XPath shown above in order to use in Selenium's FindElement?
Driver.FindElement(By.XPath("?"));
I know how to use the contains tool, but apparently not with more complex XPath statements. I was pretty sure one of the below would work but they did not (develop tool complain of a syntax error):
$x("(//label[#class='dropdown-item' and text()[2][contains(., 'Name')]]")
$x("(//label[#class='dropdown-item' and contains(text()[2], 'Name')]")
I am using the 'contains' in order to avoid white-space conflicts.
Additional for learning purposes (good for XPath debugging):
just in case anyone comes across this who is new to XPath, I wanted to show what the data structure of these label objects looked like. You can explore the data structure of objects within your webpage by using the Firefox Console window within the developer tools (F12). As you can see, the label element contains three sub-items; text which is empty, then the inpput checkbox, then some more text which has the actual text in it (not ideal). In the picture below, you can see the part of the webpage that corresponds to the label data structure.
If you are looking to find the element that contains "Name" given the HTML above, you can use
//label[#class='dropdown-item'][contains(.,'Name')]
So finally got it to work. The Firefox developer environment was correct when it stated there was a syntax problem with the XPath strings.
The following XPath string finally returned the desired result:
$x("//label[#class='dropdown-item' and contains(text()[2], 'Name')]")

Trying to use Selenium to find a specific entry in a list when what you type highlights that word

DOM:
<span class="item">Does not <span class="highlight">match</span>.</span>
<span class="item">Also not <span class="highlight">match</span>ing.</span>
<span class="item"><span class="highlight">match</span></span>
Issue:
I've got a list of items. When I type into a text box, it eliminates items that do not match, and highlights the ones that do inside a /span. The issue is that if I type something that matches multiple things, I want to select the EXACT String, and not the ones that partially match (see above DOM example... the ideal match would be the 3rd one).
So, is my only hope here to go one by one until I find my perfect match, or is there something else that I've been missing?
You are trying to find a span that has no text, with an inner span that has some highlighted text. Here is an XPath selector for that:
//span[#class='item'][not(text())]/span[#class='highlight'][‌​text()='match']

Selenium - Search for an element within element

Hi I want to hold element references in files somewhere. and then in run time search for elements withing referenced elements in Selenium how to do that.
For example- a Frame contains multiple text boxes -and multiple frames of similar properties exist where the textboxes are also duplicate. Something like I wanna reference the text box under a particular frame. But i wanna predefine the frame. and the specify that search under that frame[Something like Aliases in Testcomplete]
For Example - similar concept exist in Cheezy's Page-Objects. but not quite.
if you have a structure like this:
<div class='some class'>
<input class='input-button' value='submit'>Submit</input>
</div>
<div class='some class2'>
<input class='input-button' value='submit'>Submit</input>
</div>
and you want to find the first 'Submit' which is within the 'some class' div, you can do this:
parent_element = driver.find_element(:xpath, "//div[#class='some class']")
child_element = parent_element.find_element(:xpath, ".//input")
p.s. this is ruby code.

How do I select a particular dynamic div, using Selenium when I don't have a unique id or name?

Only the content of the div is unique. So, in the following dynamically generated html, only "My Article-1245" is unique:
<div class="col-md-4 article">
<h2>
My Article-1245
Delete
Edit
</h2>
<p>O ephemeral text! Here today, gone tomorrow. Not terribly important, but necessary</p>
</div>
How do I select the edit/delete link of this specific div, using Selenium? assertText/verifyText requires an element locator, but I do not have any unique id/name (out of my control). There will be many such div blocks, with other content text, all dynamically generated.
Any help would be appreciated.
If text 'My Article' appears each time, you may use following:
//For Delete
driver.findElement(By.xpath("//h2[contains(text(),'My Article-')]/a[text()='Delete']"));
//For Edit
driver.findElement(By.xpath("//h2[contains(text(),'My Article-')]/a[text()='Edit']"));
Hope it meets your requirement :)
Matching by text is always a bad automated testing concept. If you want to keep clean and reliable test scripts, then :
Contact your web dev to add unique identifiers to the elements
Suck it up, and create selectors based on what's there.
You are able to create a CSS selector based on what you want.
What you should do is create the selector using parent-child relationships:
driver.findElement(By.cssSelector("div.article:nth-child(X) a[href^='delete']"));
As I am ignorant of your appp, this is also assuming that all of your article classes are under the same parent. You would substitute X with the number of the div you want to refer to. e.g.:
<div id="someparent">
<div class="...article" />
<div class="...article" />
...
</div>