Click checkbox with Nested Elements in Watir - testing

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

Related

Python Selenium: If there are multiple "div" tags, how do print a specific one WITHOUT Xpath?

I am trying to learn how to print by tag. Cannot use find element by xpath or class. If there are 4 "div" tags, how do I print the contents of a specific one?
Desired Output:
vjs-poster
Attempt 1:
divs = driver.find_elements(By.TAG_NAME, "div")
print(divs[0])
Attempt 2:
divs = driver.find_elements(By.TAG_NAME, "div")
print(divs[0].get_attribute('class'))
HTML: (The third line says "vjs-poster" this is what I want to print.)
<video id="video_html5_api" class="vjs-tech" onclick="streaming();" src="/video/stream?cntId=21671&quality=sd"></video>
<div></div>
<div class="vjs-poster" tabindex="-1" style="background-image: url("https://[REDACTED].com/images/V15064/720X480/720x480/nt/4.jpg");"></div>
<div class="vjs-text-track-display vjs-hidden" aria-live="assertive" aria-atomic="true"></div>
<div class="vjs-loading-spinner" dir="ltr"></div>
To print the value of the class attribute vjs-poster of the second <div> you can use:
print(driver.find_elements(By.TAG_NAME, "div")[1].get_attribute('class'))
You can also use a css_selector as:
print(driver.find_element(By.CSS_SELECTOR, "video.vjs-tech#video_html5_api +div +div").get_attribute('class'))
You can try locating that element based on it class name and style or any one of them if the locator will still be unique.
You try this:
class_val = driver.find_elements(By.XPATH, "//div[contains(#style,'https://[REDACTED].com/images')").get_attribute('class')
print(class_val)

How to find xpath of an element which depends upon sibling class

I have below html code
<a class = sidetoolsdivider>
<div class = sideone > Test 1 </div>
<div class = sidetwo> </div>
</a>
<a class = sidetoolsdivider>
<div class = sideone > Test 2 </div>
<div class = sidetwo> </div>
</a>
...............
Here I need to find xpath locator of class sidetwo which has text Test1. There are many such similar classes hence you can differentiate between different only based on element text
The xpath would be something like below:
Since the element depends on the text, can make use of text attribute for the same.
//div[text()='Text1']/following-sibling::div
Or
//div[contains(text(),'Text1')]/following-sibling::div
Or
//div[contains(text(),'Text1')]/following-sibling::div[#class='sidetwo']
Link to refer - Link
This gets you the correct 'a'. Find an 'a' which contains the right div of sideone (note the .//, find a Child which is)
"//a[.//div[ #class='sideone" and text()='Test 1']"
Then just get the side two, complete xPath
"//a[.//div[ #class='sideone" and text()='Test 1']//div[#class='sidetwo']"
Works even if there is more text inside the entire 'a' and stuff gets complex with more elements inside.

Webelement getText() function returns different values on the same element

Following code is used to get text of specified button element with id:
EE__printer-menu__activator
In our structure it's drop-down and here is element with child elements DOM structure:
<button data-v-12817ac3="" type="button" class="some classes" id="EE__printer-menu__activator"><div class="v-btn__content">
Printer
<i data-v-12817ac3="" aria-hidden="true" class="some classes">arrow_drop_down</i>
</div>
</button>
The problem is following: when drop-down is not expanded and I'm trying to get text of id="EE__printer-menu__activator" element using getText() I receive :
{Printer
arrow_drop_down}
which is expected. but when drop-down is expanded and I'm using the same I get only text of first child:
{Printer}
Can't understand why in this case getText() doesn't return "arrow_drop_down" text of the last child of selected element.
When drop down is not extended then if you pay attention
<i data-v-12817ac3="" aria-hidden="true" class="some classes">arrow_drop_down</i>
to more particular attribute aria-hidden is set to true. so when you are calling .getText on EE__printer-menu__activator, you are getting both the text.
Now, here is a bit assumption that when drop down is expanded, then aria-hidden value will be set to false. causing .getText() to return what it has, and it does have only first Printer.

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']

How to Select a checbox by its corresponding label name

I am relatively new to xpath and I'm having an issue with Selecting a checkbox.
The following expression works fine
:xpath=//div/label[#for='chkCat2']
But I need to select a checkbox based on its label name (Music in this case)
Unfortunately, this -
xpath=.//div[label[contains(text(),'Music')]
is clicking on the label, not on the checkbox.
How is it possible to do that? I also tried this one but its not able to locate the element:
xpath=.//div[label[contains(text(),'Music')]/preceding-sibling::label]
That's the sample of the code:
<input name="ctl00$cphContent$ThreeMedia$categoriesRepeater$ctl01$ctl00"
data-bind="attr:{'id': 'chkCat' + id, 'data-id': id}, checked: selected" id="chkCat2" data-id="2" type="checkbox">
<label data-bind="attr:{'for': 'chkCat' + id}" for="chkCat2" class=" firepath-matching-node"></label>
<label class="chkbox-content margin-bottom-0" data-bind="text: name">Music</label>
Thanks for the help
But I need to select a checkbox based on its label name (Music in this case)
Assuming div is the parent element of the provided checkbox element, try using below xpath :-
.//div[normalize-space(.)='Music']/input
or more specific
.//div[normalize-space(.)='Music']/input[#type='checkbox']
one more
.//div[label[text() = 'Music']]/input
Try this below mentioned xpath
//label[text()= 'Music']/..//preceding-sibling::input[#id='chkCat2']
Explanation of xpath:- Use text method along with <label> tag and move ahead with <input> tag using preceding-sibling keyword.