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

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>

Related

How to match xpath for id element that changes each time page loads?

I have these 2 xpath that are different each time I load a webpage.
The xpaths were recorded by Selenium-IDE and always have mainForm_view within the id string and the text before and after this always changes.
xpath=//input[#id='abc_hyd_wuu2_8333nd_mainForm_view_jjd_uueue2_jjd_11_jkdhd']
xpath=//div[#id='abc_hyd_wuu2_8333nd_mainForm_view_kcjjcs_sjsjs_jjdj_994_kkk']/div/div[2]/div/div/div/a[1]/h2
I've tried to locate the id like below but doesn't work.
xpath=//input[contains(#id,'mainForm_view')]
xpath=//div[contains(#id,'mainForm_view')]
Which would be the correct way to do it?
Thanks in advance.
UPDATE
I've tried with CSS selector like below but it seems is taking another id that is within an input element
document.querySelector("input[id*='mainForm_view']").id
Examining the html code I see that the id I need is related with a unique class. The code is like below:
<div class="Class_p2">
<div class="Class_p3" style="...">
<input name="8333nd$mainForm$view$jjd$uueue2" type="text" class="class a1 n1-Control" value="xyz" id="8333nd_mainForm_view_jjd_uueue2" disabled="disabled" style="..">
</div>
<input name="8333nd$mainForm$view$ttyi" type="text" disabled="disabled">
</div>
I've tried the following Javascript code in Chrome console but it doesn't work
document.getElementsByClassName("class a1 n1-Control").id
How would be to get the id=8333nd_mainForm_view_jjd_uueue2 that is related with Class=class a1 n1-Control?
UPDATE2
I was finally able to do it with
document.getElementsByClassName("class a1 n1-Control")[0].id
Thanks for all the help and time.
You can write css selector as :
input[id*='mainForm_view']
for div it'd be :
div[id*='mainForm_view']
Asterisk is to match the sub string part.
Note that if any id contains mainForm_view that will also be selected, so better to check in developers tool before proceeding.
You can try finding some other element for which xpath/css locator remains same and then try to reach to this element by traversing from there. You can use parent, ancestor, preceding-sibling, following-sibling keywords in order to traverse. Hope it helps :)

How to populate drop down when it is built using an input tag using java and 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?

Selenium access a form field with bad id

Looking for the best approach to enter / read a value from a form field that lacks human readable ids / references.
The basic outline looks like
<div id="form-2143">
<div id="numberfield-1234">
<label id="numberfield-1234-label">
<span class="x-form-label">Field Name 1</span>
</label>
<div id="numberfield-1234-body">
<div id="numberfield-1234-wrap">
<input id="numberfield-1234-input" class="form-field" componentid="numberfield-1234">
</div>
</div>
</div>
...
</div>
There are more class defs and attributes involved, but above is the "basics" I have to work with.
This form has a number of entries, and there are more forms like it, so I am looking for a way to search for the label name, and access the input field within the same container.
I lack control of the site and cannot edit the HTML structure of the site; meaning I cannot give sensible names to the ids, but want to avoid hard referencing the poor names. Any suggestions on how to get Robot Framework & selenium to reference these elements?
Highlighting Andersson's answer in the comments
Using the XPath
//label[span[text()="Field Name 1"]]/following-sibling::div//input
Works for the above example.
The key part that answers the question of how to reference nearby elements is
/following-sibling

Get attributes of a empty child node

I want to transform a old HTML4 code to have closed tags in order to achieve compatibility with WCAG.
I have a lot of anchors without content, used as internal links, like
<h3> <a id="julio" name="julio"></a>Julio 2015</h3>
For reasons I do not understand, some browsers do not understand the self-enclosed tag, and interpret it as the start of an anchor (without end).
<h3> <a id="julio" name="julio"/a>Julio 2015</h3>
Then, I want to delete empty anchors and move the attributes to the parent tag:
<h3 id="julio" name="julio">Julio 2015</h3>
The tool I have to use only supports XSLT 1.0
How can I get it?

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.