WebDriver - finding sibling elements - selenium

I have a html markup like this:
<html>
...
<body>
....
<fieldset>
<legend>Other Details</legend>
<div>
<input type='text' id='txt1' title='Detail 01'/>
</div>
<div>
<input type='text' id='txt2' title=''/>
</div>
<div>
<input type='text' id='txt3' title=''/>
</div>
<div>
<input type='text' id='txt4' title='Detail 04'/>
</div>
</fieldset>
.....
<body>
</html>
This is what I want to do.
I need to rapidly traverse the screen, pick up all the textboxes and their titles. When I encounter a textbox that has no title (like two of them in my above example), I need to check if they occur under a fieldset, which they do. Now, for these textboxes without a title, all I have to do is to take the legend value of the fieldset and assign it to the textbox.
For example, the second and third textboxes in the above example do not have a title. In this case I want to do the following:
Take the legend value of the containig fieldset (in this case, "Other Details")
Derive the position of the textbox in the fieldset and append it to the fielset legend like Other Details 2
Do the same thing for the third textbox.
I achieved step 1. When I am in step 2, I need to find out the position of the textbox in the parent fieldset. I have my selenium webdriver code below:
WebElement textbox = driver.findElement(By.id("txt2"));
List<WebElement> precedingSiblings =
textbox.findElement(By.xpath("preceding-sibling::input[#type='text' or #type='Text' or #type='TEXT']"));
String myTitle =
fieldSetLegend + " " + Integer.toString(precedingSiblings.size()+1);
I expect this code to give me the value of myTitle to be Other Details 2 and Other Details 3 for my second and third textboxes.
But the problem is, everytime I hit precedingSiblings.size(), it always returns 0. That is because each input is contained within a div and hence has no siblings.
Now, I want to know of a way through which I can find at what position my current element is within the containing fieldset.
Please help.!!!

What about navigating to the parent div finding it's preceding sibling & then finding the relevant input from there.
Roughly:
parent::div/preceding-sibling::div/input[#type='text' or #type='Text' or #type='TEXT']

Related

How to write xpath for a field and validate the fields

I have a requirement to verify field name and values. My code looks like
<div class="line info">
<div class="unit labelInfo TextMdB">
Reference #:
</div>
<div class="unit lastUnit">
701
</div>
</div>
</div>
<div class="line info">
<div class="unit labelInfo TextMdB">
Registered Date:
</div>
<div class="unit lastUnit">
05/05/2020
</div>
</div>
I gave my xpath as
"//div[#class='unit lastUnit']//preceding-sibling::div[#class='unit labelInfo TextMdB' and contains(text(),'Reference #:')]".
With this xpath I am able to reach "reference#" field . But how to verify reference # field is displaying the value (in this case 701) .
Appreciate your response.
Thanks
You can first reach the Reference # text by using its text in the xpath and then you can use following-sibling to fetch the div tag and then use getText()(java) / text (python) method to get 701.
(Edited answer after OP's comment)
If you want to check if the element is displayed on the page or not then you can fetch its list and check if the size of that list is greater than 0 or not.
You can do it like:
In Java:
List<WebElement> elementList = driver.findElements(By.xpath("//div[#class='line info']//div[contains(text(),'Reference #')]//following-sibling::div"));
if(elementList.size()>0){
// Element is present on the UI
// Finding its text
String text = elementList.get(0).getText();
}
In python:
elementList = driver.find_elements_by_xpath("//div[#class='line info']//div[contains(text(),'Reference #')]//following-sibling::div")
if (elementList.len>0):
# Element is present
# Printing its text
print(elementList[0].text)

Xpath not finding element (parent/ancestor)

<div class="slds-show" data-aura-rendered-by="10155:0">
<div class="footer" data-aura-rendered-by="10156:0">
<div class="slds-grid slds-grid--align-end slds-m-top--large" data-aura-rendered-by="10157:0">
<div class="slds-show" data-aura-rendered-by="10158:0">
<button class="slds-button slds-button--neutral slds-m-left--small" data-aura-rendered-by="10159:0">Cancel</button>
<button class="slds-button slds-button--neutral slds-m-left--small" data-aura-rendered-by="10161:0">Save & New</button>
<button class="slds-button slds-button--brand slds-m-left--small" data-aura-rendered-by="10163:0">Save</button>
</div>
</div>
</div>
This is part of page, on which I will have to click on Save button.
Button is not unique and I need to find it throu class attribute from first div (slds-show), or
Can somebody tell me, why this xpath is not finding this element?
//button[parent::div[#class='slds-show'][#class='slds-button slds-button--brand slds-m-left--small']]
I've also try with ancestor, text instead of class and results is the same. Element is not found via Firefox console
To click on Save button once finding it through class attribute from first div (slds-show) you can use a much simpler and effective xpath as follows :
//div[#class='slds-show']/button[#class='slds-button slds-button--brand slds-m-left--small']
Note : The class attribute slds-button--brand is unique for the Save button.
Try to update your expression as below:
//button[parent::div[#class='slds-show'] and #class='slds-button slds-button--brand slds-m-left--small']
Note that predicate [#class='slds-button slds-button--brand slds-m-left--small'] in your XPath intend to test #class value of parent div, but not target button
You can try the following xpaths.
//*[#class="slds-show"]/button[text()="Save"]
or
//*[class="slds-show"]/button[#class="slds-button slds-button--brand slds-m-left--small"]
An xpath can easily get too complex, you can also try something like this:
//button[text()='Cancel']
//button[text()='Save & New']
//button[text()='Save']
These will return the exact buttons you need. If you're looking for a specific ancestor, include it in your xpath:
//div[#class="slds-show"]//button[text()='Save & New']

Read the label of a Radio Button and confirm the value with Selenium

So as the title suggests. I am looking to confirm that the value of the Radio button is correct.
The HTML is as follows:
<input type="radio" value="Coach" name="servClass" checked="">
<font face="Arial, Helvetica, sans-serif">
Economy class
<br>
<input type="radio" value="Business" name="servClass">
Business class
<br>
<input type="radio" value="First" name="servClass">
First class
</font>
The selenium bit is as follows:
String expectedServiceClass = "First class";
String actualServiceClass = driver.findElement(By.cssSelector("input[value='First']")).getText();
if (actualserviceClass.equals(expectedServiceClass)){
System.out.println("Correct Wording");
}else{
System.out.println("Oops: somethings not right with the wording");
//close Firefox
driver.close();
// exit the program explicitly
System.exit(0);
}
But when this is executed, the actualServiceClass variable doesn't contain any values i.e. null therefore the "if statement" will always print "Oops: somethings not right with the wording"
Any help???
With the current HTML code, you won't be able to confirm the value of label of Radio button as Radio button is implemented as Input tag, that is a self-closing tag and hence getText() on input will always return null. You will need a container tag like div to include the Input tag(radio button) and the label. Refer: Self-closed versus Container Tags
The problem is not with the Selenium Code, its actually due to the improper HTML snippet. Changing the HTML as below can solve this:
<font face="Arial, Helvetica, sans-serif">
<div>
<input type="radio" value="Coach" name="servClass" checked="">
Economy class
<br>
</div>
<div>
<input type="radio" value="Business" name="servClass">
Business class
<br>
</div>
<div>
<input type="radio" value="First" name="servClass">
First class
</div>
After this, just changing the Css Selector or XPath to find the div will give you value of label of Radio Button. Css Selector can be div>input[value='First']. Let me know if you are able to solve the problem.
I agree with #Manu the HTML snippet is poor but you can use javascript childNodes to get the text from the nodes
The childNodes property returns a collection of a node's child nodes, as a NodeList object.
The nodes in the collection are sorted as they appear in the source code and can be accessed by index numbers. The index starts at 0.
Use executescript to execute JavaScript in the context of the currently selected frame or window
Below is an example in java
Don't forget to add return since you need to return the value to the caller
WebElement element = driver.findElement(By.xpath("//input[#value='Coach']/following-sibling::font"));
String node_text=(String)((JavascriptExecutor)driver).executeScript("return arguments[0].childNodes[0].nodeValue",element);
System.out.println(node_text.trim());
Try the above script it will return "Economy class"
In the above script we use childnode property to get all the childnodes of
font tag <font face="Arial, Helvetica, sans-serif">
similarly you can get the other text nodes by replacing childnode index
childNodes[4]----->"Business class"
childNodes[8]------>"First class"
I tried the above code it was working fine
Hope this helps you...kindly get back if you have any queries

Click checkbox with Nested Elements in Watir

I'll try to keep it simple.
I have a list of similar rows like this:
HTML code:
<li ...>
<div ... >
<some elements here>
</div>
<input id="121099" class="containerMultiSelect" type="checkbox" value="121099" name="NodeIds">
<a ...>
<div ... />
<div ... >
<h2>Identified Text</h2>
<h3>...</h3>
</div>
</a>
</li>
I want to click the checkbox with a certain text, but I can't use any of its elements, because they are the same for all the list, and id is generated automatically. The only thing can be differentiated is the h2 text. I tried :
browser.h2(:text => /Identified/).checkbox(:name => "NodeIds").set
and I got UnknownException which is obvious because checkbox is not nested with a tag.
What can I do in this case?
Thanks
The h2 and checkbox are related by the li, which is a common ancestor. Therefore, to find the checkbox, you can look for the li that contains the h2 element. I find the most readable approach to doing this is by using the find method of the element collection. The find method basically allows you to make custom locators.
The code would be:
parent_li = browser.lis.find do |li|
li.h2(:text => 'Identified Text').present?
end
parent_li.checkbox.set
Notes:
browser.lis creates a collection of all li elements.
find iterates through the lis and returns the first element that has the block evaluate as true - ie the first li where an h2 with the specified text is present.
First have a look at this explanation
http://jkotests.wordpress.com/2012/12/20/finding-a-parent-element-that-matches-a-specific-criteria/
Now following a similar approach,
First locate the element that has a unique identifier
parent=#browser.h2(:text=>"Identified Text")
Now we have to iterate over to the parent element which contains both the checkbox and text against it.
parent=parent.parent until parent.tag_name=="li"
Once the control is on the li element, simple click on the checkbox using.
parent.checkbox.click

Selenium problem locating by DOM

I'm trying to use the DOM to locate a form element in Selenium but I can't get it to work. Even if I use the example in the Selenium documentation it still fails, for example with this html...
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
and this command in the Selenium IDE...
verifyElementPresent
with target...
dom=document.forms['loginForm']
I get [error] false in the log.
The 'getElementById' example in the documentation does work, but none of the others.
Can someone explain what I'm doing wrong here?
Thanks.
Not sure why it's not working (I can replicate the problem), but perhaps there's a better way to locate your target element? I would recommend locating by ID/name, falling back to CSS or XPath.
The format to locate a element is-
i) document.forms[index of the form].elements[index of the element]
index of the form = the index number (starting at 0) of the form with respect to the whole page, index of the element = the index number (starting at 0) of the element with respect to the whole form that contains it.
ii) document.forms[“name of the form”].elements[“name of the element”]
name of the form = the value of the name attribute of the form tag that contains the element you want to access, name of the element = the value of the name attribute of the element you wish to access
iii) document.getElementById(“id of the element”)
id of the element = this is the value of the ID attribute of the element to be accessed. This value should always be enclosed in a pair of parentheses (“”).
iv)document.getElementsByName(“name”)[index]
name = name of the element as defined by its ‘name’ attribute, index = an integer that indicates which element within getElementsByName’s array will be used.